diff options
author | Leahy, Leroy P <leroy.p.leahy@intel.com> | 2016-05-02 12:59:17 -0700 |
---|---|---|
committer | Prince Agyeman <prince.agyeman@intel.com> | 2016-05-02 15:46:44 -0700 |
commit | 81a23a0fee462de44f8e15fc6939a4b729d3e102 (patch) | |
tree | 51c45440b3c55491d1336dd24c60c1f6bbcfb5b3 /CorebootModulePkg | |
parent | 13986b690ce803ca607837b57c6c437f8027f3a2 (diff) | |
download | edk2-platforms-81a23a0fee462de44f8e15fc6939a4b729d3e102.tar.xz |
CorebootModulePkg: Remove DuetPkg references
Remove the references to DuetPkg. Copy the files from revision
ffea0a2ce21e8e9878587de2419959a7bfea4021 of DuetPkg into
CorebootModulePkg. The components include:
* PciBusNoEnumerationDxe
* PciRootBridgeNoEnumerationDxe
* SataControllerDxe
TEST=Build and run on Galileo Gen2
Change-Id: Id07185f7e226749e5f7c6b6cb427bcef7eac8496
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Lee Leahy <leroy.p.leahy@intel.com>
Reviewed-by: Maurice Ma <maurice.ma@intel.com>
Reviewed-by: Prince Agyeman <prince.agyeman@intel.com>
Diffstat (limited to 'CorebootModulePkg')
36 files changed, 15249 insertions, 0 deletions
diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/ComponentName.c b/CorebootModulePkg/PciBusNoEnumerationDxe/ComponentName.c new file mode 100644 index 0000000000..9419f9a3e8 --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/ComponentName.c @@ -0,0 +1,161 @@ +/*++ + +Copyright (c) 2005 - 2007, 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: + ComponentName.c + +Abstract: + +--*/ + +#include "PciBus.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +PciBusComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +PciBusComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gPciBusComponentName = { + PciBusComponentNameGetDriverName, + PciBusComponentNameGetControllerName, + "eng" +}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gPciBusComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) PciBusComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) PciBusComponentNameGetControllerName, + "en" +}; + + +EFI_UNICODE_STRING_TABLE mPciBusDriverNameTable[] = { + { "eng;en", L"PCI Bus Driver" }, + { NULL, NULL } +}; + +EFI_STATUS +EFIAPI +PciBusComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + Language - A pointer to a three character ISO 639-2 language identifier. + This is the language of the driver name that that the caller + is requesting, and it must match one of the languages specified + in SupportedLanguages. The number of languages supported by a + driver is up to the driver writer. + DriverName - A pointer to the Unicode string to return. This Unicode string + is the name of the driver specified by This in the language + specified by Language. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mPciBusDriverNameTable, + DriverName, + (BOOLEAN)(This == &gPciBusComponentName) + ); +} + +EFI_STATUS +EFIAPI +PciBusComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + ControllerHandle - The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + ChildHandle - The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + Language - A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + ControllerName - A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language specified + by Language from the point of view of the driver specified + by This. + + Returns: + EFI_SUCCESS - The Unicode string for the user readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return EFI_UNSUPPORTED; +} diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciBus.c b/CorebootModulePkg/PciBusNoEnumerationDxe/PciBus.c new file mode 100644 index 0000000000..aa33162269 --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciBus.c @@ -0,0 +1,346 @@ +/*++ + +Copyright (c) 2005 - 2006, 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: + + PciBus.c + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#include "PciBus.h" + +// +// PCI Bus Support Function Prototypes +// + +EFI_STATUS +EFIAPI +PciBusEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +PciBusDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +PciBusDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +PciBusDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + + +// +// PCI Bus Driver Global Variables +// + +EFI_DRIVER_BINDING_PROTOCOL gPciBusDriverBinding = { + PciBusDriverBindingSupported, + PciBusDriverBindingStart, + PciBusDriverBindingStop, + 0xa, + NULL, + NULL +}; + +BOOLEAN gFullEnumeration; + +UINT64 gAllOne = 0xFFFFFFFFFFFFFFFFULL; +UINT64 gAllZero = 0; + +// +// PCI Bus Driver Support Functions +// +EFI_STATUS +EFIAPI +PciBusEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + + Initialize the global variables + publish the driver binding protocol + +Arguments: + + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + +Returns: + + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + EFI_STATUS Status; + + // + // Initialize the EFI Driver Library + // + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gPciBusDriverBinding, + ImageHandle, + &gPciBusComponentName, + &gPciBusComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + InitializePciDevicePool (); + + gFullEnumeration = TRUE; + + return Status; +} + +EFI_STATUS +EFIAPI +PciBusDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + Check to see if pci bus driver supports the given controller + +Arguments: + + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + +Returns: + + EFI_SUCCESS + +--*/ +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + EFI_DEV_PATH_PTR Node; + + if (RemainingDevicePath != NULL) { + Node.DevPath = RemainingDevicePath; + if (Node.DevPath->Type != HARDWARE_DEVICE_PATH || + Node.DevPath->SubType != HW_PCI_DP || + DevicePathNodeLength(Node.DevPath) != sizeof(PCI_DEVICE_PATH)) { + return EFI_UNSUPPORTED; + } + } + // + // Open the IO Abstraction(s) needed to perform the supported test + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &ParentDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciRootBridgeIoProtocolGuid, + (VOID **) &PciRootBridgeIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->CloseProtocol ( + Controller, + &gEfiPciRootBridgeIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PciBusDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + Start to management the controller passed in + +Arguments: + + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + +Returns: + + +--*/ +{ + EFI_STATUS Status; + + // + // Enumerate the entire host bridge + // After enumeration, a database that records all the device information will be created + // + // + Status = PciEnumerator (Controller); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Enable PCI device specified by remaining device path. BDS or other driver can call the + // start more than once. + // + + StartPciDevices (Controller, RemainingDevicePath); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PciBusDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + +Routine Description: + + Stop one or more children created at start of pci bus driver + if all the the children get closed, close the protocol + +Arguments: + + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + +Returns: + + +--*/ +{ + EFI_STATUS Status; + UINTN Index; + BOOLEAN AllChildrenStopped; + + if (NumberOfChildren == 0) { + // + // Close the bus driver + // + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->CloseProtocol ( + Controller, + &gEfiPciRootBridgeIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + DestroyRootBridgeByHandle ( + Controller + ); + + return EFI_SUCCESS; + } + + // + // Stop all the children + // + + AllChildrenStopped = TRUE; + + for (Index = 0; Index < NumberOfChildren; Index++) { + + // + // De register all the pci device + // + Status = DeRegisterPciDevice (Controller, ChildHandleBuffer[Index]); + + if (EFI_ERROR (Status)) { + AllChildrenStopped = FALSE; + } + } + + if (!AllChildrenStopped) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciBus.h b/CorebootModulePkg/PciBusNoEnumerationDxe/PciBus.h new file mode 100644 index 0000000000..9c182086de --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciBus.h @@ -0,0 +1,225 @@ +/*++ + +Copyright (c) 2005 - 2007, 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: + + PciBus.h + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#ifndef _EFI_PCI_BUS_H +#define _EFI_PCI_BUS_H + +#include <PiDxe.h> + +#include <Protocol/PciIo.h> +#include <Protocol/PciRootBridgeIo.h> +#include <Protocol/DevicePath.h> +#include <Protocol/Decompress.h> +#include <Protocol/UgaIo.h> +#include <Protocol/LoadedImage.h> +#include <Protocol/BusSpecificDriverOverride.h> + +#include <Guid/PciOptionRomTable.h> + +#include <IndustryStandard/Pci.h> +#include <IndustryStandard/Acpi.h> +#include <IndustryStandard/PeImage.h> + +#include <Library/DebugLib.h> +#include <Library/UefiDriverEntryPoint.h> +#include <Library/BaseLib.h> +#include <Library/UefiLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/ReportStatusCodeLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/DevicePathLib.h> +#include <Library/PcdLib.h> +#include <Library/PeCoffLib.h> + +// +// Driver Produced Protocol Prototypes +// + +#define VGABASE1 0x3B0 +#define VGALIMIT1 0x3BB + +#define VGABASE2 0x3C0 +#define VGALIMIT2 0x3DF + +#define ISABASE 0x100 +#define ISALIMIT 0x3FF + +typedef enum { + PciBarTypeUnknown = 0, + PciBarTypeIo16, + PciBarTypeIo32, + PciBarTypeMem32, + PciBarTypePMem32, + PciBarTypeMem64, + PciBarTypePMem64, + PciBarTypeIo, + PciBarTypeMem, + PciBarTypeMaxType +} PCI_BAR_TYPE; + +typedef struct { + UINT64 BaseAddress; + UINT64 Length; + UINT64 Alignment; + PCI_BAR_TYPE BarType; + BOOLEAN Prefetchable; + UINT8 MemType; + UINT8 Offset; +} PCI_BAR; + +#define PCI_IO_DEVICE_SIGNATURE SIGNATURE_32 ('p','c','i','o') + +#define EFI_BRIDGE_IO32_DECODE_SUPPORTED 0x0001 +#define EFI_BRIDGE_PMEM32_DECODE_SUPPORTED 0x0002 +#define EFI_BRIDGE_PMEM64_DECODE_SUPPORTED 0x0004 +#define EFI_BRIDGE_IO16_DECODE_SUPPORTED 0x0008 +#define EFI_BRIDGE_PMEM_MEM_COMBINE_SUPPORTED 0x0010 +#define EFI_BRIDGE_MEM64_DECODE_SUPPORTED 0x0020 +#define EFI_BRIDGE_MEM32_DECODE_SUPPORTED 0x0040 + + +typedef struct _PCI_IO_DEVICE { + UINT32 Signature; + EFI_HANDLE Handle; + EFI_PCI_IO_PROTOCOL PciIo; + LIST_ENTRY Link; + + EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL PciDriverOverride; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + + // + // PCI configuration space header type + // + PCI_TYPE00 Pci; + + // + // Bus number, Device number, Function number + // + UINT8 BusNumber; + UINT8 DeviceNumber; + UINT8 FunctionNumber; + + // + // BAR for this PCI Device + // + PCI_BAR PciBar[PCI_MAX_BAR]; + + // + // The bridge device this pci device is subject to + // + struct _PCI_IO_DEVICE *Parent; + + // + // A linked list for children Pci Device if it is bridge device + // + LIST_ENTRY ChildList; + + // + // TURE if the PCI bus driver creates the handle for this PCI device + // + BOOLEAN Registered; + + // + // TRUE if the PCI bus driver successfully allocates the resource required by + // this PCI device + // + BOOLEAN Allocated; + + // + // The attribute this PCI device currently set + // + UINT64 Attributes; + + // + // The attributes this PCI device actually supports + // + UINT64 Supports; + + // + // The resource decode the bridge supports + // + UINT32 Decodes; + + // + // The OptionRom Size + // + UINT64 RomSize; + + // + // TRUE if there is any EFI driver in the OptionRom + // + BOOLEAN BusOverride; + + // + // A list tracking reserved resource on a bridge device + // + LIST_ENTRY ReservedResourceList; + + // + // A list tracking image handle of platform specific overriding driver + // + LIST_ENTRY OptionRomDriverList; + + BOOLEAN IsPciExp; + +} PCI_IO_DEVICE; + + +#define PCI_IO_DEVICE_FROM_PCI_IO_THIS(a) \ + CR (a, PCI_IO_DEVICE, PciIo, PCI_IO_DEVICE_SIGNATURE) + +#define PCI_IO_DEVICE_FROM_PCI_DRIVER_OVERRIDE_THIS(a) \ + CR (a, PCI_IO_DEVICE, PciDriverOverride, PCI_IO_DEVICE_SIGNATURE) + +#define PCI_IO_DEVICE_FROM_LINK(a) \ + CR (a, PCI_IO_DEVICE, Link, PCI_IO_DEVICE_SIGNATURE) + +// +// Global Variables +// +extern EFI_COMPONENT_NAME_PROTOCOL gPciBusComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gPciBusComponentName2; +extern EFI_DRIVER_BINDING_PROTOCOL gPciBusDriverBinding; + +extern BOOLEAN gFullEnumeration; +extern UINT64 gAllOne; +extern UINT64 gAllZero; + +#include "PciIo.h" +#include "PciCommand.h" +#include "PciDeviceSupport.h" +#include "PciEnumerator.h" +#include "PciEnumeratorSupport.h" +#include "PciDriverOverride.h" +#include "PciRomTable.h" +#include "PciOptionRomSupport.h" +#include "PciPowerManagement.h" + + +#define IS_ISA_BRIDGE(_p) IS_CLASS2 (_p, PCI_CLASS_BRIDGE, PCI_CLASS_BRIDGE_ISA) +#define IS_INTEL_ISA_BRIDGE(_p) (IS_CLASS2 (_p, PCI_CLASS_BRIDGE, PCI_CLASS_BRIDGE_ISA_PDECODE) && ((_p)->Hdr.VendorId == 0x8086) && ((_p)->Hdr.DeviceId == 0x7110)) +#define IS_PCI_GFX(_p) IS_CLASS2 (_p, PCI_CLASS_DISPLAY, PCI_CLASS_DISPLAY_OTHER) + +#endif diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciBusNoEnumeration.inf b/CorebootModulePkg/PciBusNoEnumerationDxe/PciBusNoEnumeration.inf new file mode 100644 index 0000000000..b6ec9c0f07 --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciBusNoEnumeration.inf @@ -0,0 +1,72 @@ +## @file +# +# Copyright (c) 2005 - 2010, 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: +# +# Abstract: +# +## +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PciBusNoEnumerationDxe + FILE_GUID = 35C0C168-2607-4e51-BB53-448E3ED1A87F + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = PciBusEntryPoint + +[Packages] + MdePkg/MdePkg.dec + DuetPkg/DuetPkg.dec + +[LibraryClasses] + DebugLib + BaseLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + BaseMemoryLib + ReportStatusCodeLib + DevicePathLib + PeCoffLib + +[Sources] + PciBus.h + PciIo.h + PciCommand.h + PciDeviceSupport.h + PciEnumerator.h + PciEnumeratorSupport.h + PciOptionRomSupport.h + PciRomTable.h + PciPowerManagement.h + PciPowerManagement.c + PciRomTable.c + PciDriverOverride.h + PciDriverOverride.c + PciOptionRomSupport.c + PciEnumerator.c + PciEnumeratorSupport.c + PciCommand.c + ComponentName.c + PciDeviceSupport.c + PciBus.c + PciIo.c + +[Protocols] + gEfiPciRootBridgeIoProtocolGuid + gEfiPciIoProtocolGuid + gEfiDevicePathProtocolGuid + gEfiBusSpecificDriverOverrideProtocolGuid + gEfiDecompressProtocolGuid + +[Guids] + gEfiPciOptionRomTableGuid diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciCommand.c b/CorebootModulePkg/PciBusNoEnumerationDxe/PciCommand.c new file mode 100644 index 0000000000..6682830b0f --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciCommand.c @@ -0,0 +1,453 @@ +/*++ + +Copyright (c) 2005 - 2006, 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: + + PciCommand.c + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#include "PciBus.h" + + +EFI_STATUS +PciReadCommandRegister ( + IN PCI_IO_DEVICE *PciIoDevice, + OUT UINT16 *Command +) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + + EFI_PCI_IO_PROTOCOL *PciIo; + + *Command = 0; + PciIo = &PciIoDevice->PciIo; + + return PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint16, + PCI_COMMAND_OFFSET, + 1, + Command + ); +} + +EFI_STATUS +PciSetCommandRegister ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT16 Command +) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + UINT16 Temp; + EFI_PCI_IO_PROTOCOL *PciIo; + + Temp = Command; + PciIo = &PciIoDevice->PciIo; + + return PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint16, + PCI_COMMAND_OFFSET, + 1, + &Temp + ); + +} + + +EFI_STATUS +PciEnableCommandRegister ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT16 Command +) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + UINT16 OldCommand; + EFI_PCI_IO_PROTOCOL *PciIo; + + OldCommand = 0; + PciIo = &PciIoDevice->PciIo; + + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint16, + PCI_COMMAND_OFFSET, + 1, + &OldCommand + ); + + OldCommand = (UINT16) (OldCommand | Command); + + return PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint16, + PCI_COMMAND_OFFSET, + 1, + &OldCommand + ); + +} + + +EFI_STATUS +PciDisableCommandRegister ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT16 Command +) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + UINT16 OldCommand; + EFI_PCI_IO_PROTOCOL *PciIo; + + OldCommand = 0; + PciIo = &PciIoDevice->PciIo; + + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint16, + PCI_COMMAND_OFFSET, + 1, + &OldCommand + ); + + OldCommand = (UINT16) (OldCommand & ~(Command)); + + return PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint16, + PCI_COMMAND_OFFSET, + 1, + &OldCommand + ); + +} + + + +EFI_STATUS +PciSetBridgeControlRegister ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT16 Command +) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + UINT16 Temp; + EFI_PCI_IO_PROTOCOL *PciIo; + + Temp = Command; + PciIo = &PciIoDevice->PciIo; + + return PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint16, + PCI_BRIDGE_CONTROL_REGISTER_OFFSET, + 1, + &Temp + ); + +} + + +EFI_STATUS +PciEnableBridgeControlRegister ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT16 Command +) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + UINT16 OldCommand; + EFI_PCI_IO_PROTOCOL *PciIo; + + OldCommand = 0; + PciIo = &PciIoDevice->PciIo; + + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint16, + PCI_BRIDGE_CONTROL_REGISTER_OFFSET, + 1, + &OldCommand + ); + + OldCommand = (UINT16) (OldCommand | Command); + + return PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint16, + PCI_BRIDGE_CONTROL_REGISTER_OFFSET, + 1, + &OldCommand + ); + +} + +EFI_STATUS +PciDisableBridgeControlRegister ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT16 Command +) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + UINT16 OldCommand; + EFI_PCI_IO_PROTOCOL *PciIo; + + OldCommand = 0; + PciIo = &PciIoDevice->PciIo; + + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint16, + PCI_BRIDGE_CONTROL_REGISTER_OFFSET, + 1, + &OldCommand + ); + + OldCommand = (UINT16) (OldCommand & ~(Command)); + + return PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint16, + PCI_BRIDGE_CONTROL_REGISTER_OFFSET, + 1, + &OldCommand + ); + +} + + + +EFI_STATUS +PciReadBridgeControlRegister ( + IN PCI_IO_DEVICE *PciIoDevice, + OUT UINT16 *Command +) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + + EFI_PCI_IO_PROTOCOL *PciIo; + + *Command = 0; + PciIo = &PciIoDevice->PciIo; + + return PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint16, + PCI_BRIDGE_CONTROL_REGISTER_OFFSET, + 1, + Command + ); + +} + +BOOLEAN +PciCapabilitySupport ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciIoDevice - add argument and description to function comment +{ + + if (PciIoDevice->Pci.Hdr.Status & EFI_PCI_STATUS_CAPABILITY) { + return TRUE; + } + + return FALSE; +} + +EFI_STATUS +LocateCapabilityRegBlock ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT8 CapId, + IN OUT UINT8 *Offset, + OUT UINT8 *NextRegBlock OPTIONAL + ) +/*++ + +Routine Description: + + Locate Capability register. + +Arguments: + + PciIoDevice - A pointer to the PCI_IO_DEVICE. + CapId - The capability ID. + Offset - A pointer to the offset. + As input: the default offset; + As output: the offset of the found block. + NextRegBlock - An optional pointer to return the value of next block. + +Returns: + + EFI_UNSUPPORTED - The Pci Io device is not supported. + EFI_NOT_FOUND - The Pci Io device cannot be found. + EFI_SUCCESS - The Pci Io device is successfully located. + +--*/ +{ + UINT8 CapabilityPtr; + UINT16 CapabilityEntry; + UINT8 CapabilityID; + + // + // To check the capability of this device supports + // + if (!PciCapabilitySupport (PciIoDevice)) { + return EFI_UNSUPPORTED; + } + + if (*Offset != 0) { + CapabilityPtr = *Offset; + } else { + + CapabilityPtr = 0; + if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) { + + PciIoDevice->PciIo.Pci.Read ( + &PciIoDevice->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_CARDBUS_BRIDGE_CAPABILITY_PTR, + 1, + &CapabilityPtr + ); + } else { + + PciIoDevice->PciIo.Pci.Read ( + &PciIoDevice->PciIo, + EfiPciIoWidthUint8, + PCI_CAPBILITY_POINTER_OFFSET, + 1, + &CapabilityPtr + ); + } + } + + while ((CapabilityPtr >= 0x40) && ((CapabilityPtr & 0x03) == 0x00)) { + PciIoDevice->PciIo.Pci.Read ( + &PciIoDevice->PciIo, + EfiPciIoWidthUint16, + CapabilityPtr, + 1, + &CapabilityEntry + ); + + CapabilityID = (UINT8) CapabilityEntry; + + if (CapabilityID == CapId) { + *Offset = CapabilityPtr; + if (NextRegBlock != NULL) { + *NextRegBlock = (UINT8) (CapabilityEntry >> 8); + } + + return EFI_SUCCESS; + } + + CapabilityPtr = (UINT8) (CapabilityEntry >> 8); + } + + return EFI_NOT_FOUND; +} diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciCommand.h b/CorebootModulePkg/PciBusNoEnumerationDxe/PciCommand.h new file mode 100644 index 0000000000..da67b7844c --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciCommand.h @@ -0,0 +1,167 @@ +/*++ + +Copyright (c) 2005 - 2006, 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: + + PciCommand.h + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#ifndef _EFI_PCI_COMMAND_H +#define _EFI_PCI_COMMAND_H + +#include "PciBus.h" + +// +// The PCI Command register bits owned by PCI Bus driver. +// +// They should be cleared at the beginning. The other registers +// are owned by chipset, we should not touch them. +// +#define EFI_PCI_COMMAND_BITS_OWNED ( \ + EFI_PCI_COMMAND_IO_SPACE | \ + EFI_PCI_COMMAND_MEMORY_SPACE | \ + EFI_PCI_COMMAND_BUS_MASTER | \ + EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE | \ + EFI_PCI_COMMAND_VGA_PALETTE_SNOOP | \ + EFI_PCI_COMMAND_FAST_BACK_TO_BACK \ + ) + +// +// The PCI Bridge Control register bits owned by PCI Bus driver. +// +// They should be cleared at the beginning. The other registers +// are owned by chipset, we should not touch them. +// +#define EFI_PCI_BRIDGE_CONTROL_BITS_OWNED ( \ + EFI_PCI_BRIDGE_CONTROL_ISA | \ + EFI_PCI_BRIDGE_CONTROL_VGA | \ + EFI_PCI_BRIDGE_CONTROL_VGA_16 | \ + EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK \ + ) + +// +// The PCCard Bridge Control register bits owned by PCI Bus driver. +// +// They should be cleared at the beginning. The other registers +// are owned by chipset, we should not touch them. +// +#define EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED ( \ + EFI_PCI_BRIDGE_CONTROL_ISA | \ + EFI_PCI_BRIDGE_CONTROL_VGA | \ + EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK \ + ) + +EFI_STATUS +PciReadCommandRegister ( + IN PCI_IO_DEVICE *PciIoDevice, + OUT UINT16 *Command +); + + +EFI_STATUS +PciSetCommandRegister ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT16 Command +); + +EFI_STATUS +PciEnableCommandRegister ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT16 Command +); + +EFI_STATUS +PciDisableCommandRegister ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT16 Command +); + +EFI_STATUS +PciDisableBridgeControlRegister ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT16 Command +); + + +EFI_STATUS +PciEnableBridgeControlRegister ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT16 Command +); + +EFI_STATUS +PciReadBridgeControlRegister ( + IN PCI_IO_DEVICE *PciIoDevice, + OUT UINT16 *Command +); + +BOOLEAN +PciCapabilitySupport ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +LocateCapabilityRegBlock ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINT8 CapId, + IN OUT UINT8 *Offset, + OUT UINT8 *NextRegBlock OPTIONAL + ) +/*++ + +Routine Description: + + Locate Capability register. + +Arguments: + + PciIoDevice - A pointer to the PCI_IO_DEVICE. + CapId - The capability ID. + Offset - A pointer to the offset. + As input: the default offset; + As output: the offset of the found block. + NextRegBlock - An optional pointer to return the value of next block. + +Returns: + + EFI_UNSUPPORTED - The Pci Io device is not supported. + EFI_NOT_FOUND - The Pci Io device cannot be found. + EFI_SUCCESS - The Pci Io device is successfully located. + +--*/ +; + + +#endif + diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciDeviceSupport.c b/CorebootModulePkg/PciBusNoEnumerationDxe/PciDeviceSupport.c new file mode 100644 index 0000000000..97a4e01c27 --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciDeviceSupport.c @@ -0,0 +1,973 @@ +/*++ + +Copyright (c) 2005 - 2006, 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: + + PciDeviceSupport.c + +Abstract: + + This file provides routine to support Pci device node manipulation + +Revision History + +--*/ + +#include "PciBus.h" + +// +// This device structure is serviced as a header. +// Its Next field points to the first root bridge device node +// +LIST_ENTRY gPciDevicePool; + +EFI_STATUS +InitializePciDevicePool ( + VOID + ) +/*++ + +Routine Description: + + Initialize the gPciDevicePool + +Arguments: + +Returns: + + None + +--*/ +{ + InitializeListHead (&gPciDevicePool); + + return EFI_SUCCESS; +} + +EFI_STATUS +InsertRootBridge ( + IN PCI_IO_DEVICE *RootBridge + ) +/*++ + +Routine Description: + + Insert a root bridge into PCI device pool + +Arguments: + + RootBridge - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +{ + InsertTailList (&gPciDevicePool, &(RootBridge->Link)); + + return EFI_SUCCESS; +} + +EFI_STATUS +InsertPciDevice ( + PCI_IO_DEVICE *Bridge, + PCI_IO_DEVICE *PciDeviceNode + ) +/*++ + +Routine Description: + + This function is used to insert a PCI device node under + a bridge + +Arguments: + Bridge - A pointer to the PCI_IO_DEVICE. + PciDeviceNode - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ + +{ + + InsertTailList (&Bridge->ChildList, &(PciDeviceNode->Link)); + PciDeviceNode->Parent = Bridge; + + return EFI_SUCCESS; +} + +EFI_STATUS +DestroyRootBridge ( + IN PCI_IO_DEVICE *RootBridge + ) +/*++ + +Routine Description: + + +Arguments: + + RootBridge - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +{ + DestroyPciDeviceTree (RootBridge); + + gBS->FreePool (RootBridge); + + return EFI_SUCCESS; +} + +EFI_STATUS +DestroyPciDeviceTree ( + IN PCI_IO_DEVICE *Bridge + ) +/*++ + +Routine Description: + + Destroy all the pci device node under the bridge. + Bridge itself is not included. + +Arguments: + + Bridge - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +{ + LIST_ENTRY *CurrentLink; + PCI_IO_DEVICE *Temp; + + while (!IsListEmpty (&Bridge->ChildList)) { + + CurrentLink = Bridge->ChildList.ForwardLink; + + // + // Remove this node from the linked list + // + RemoveEntryList (CurrentLink); + + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + + if (IS_PCI_BRIDGE (&(Temp->Pci))) { + DestroyPciDeviceTree (Temp); + } + gBS->FreePool (Temp); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +DestroyRootBridgeByHandle ( + EFI_HANDLE Controller + ) +/*++ + +Routine Description: + + Destroy all device nodes under the root bridge + specified by Controller. + The root bridge itself is also included. + +Arguments: + + Controller - An efi handle. + +Returns: + + None + +--*/ +{ + + LIST_ENTRY *CurrentLink; + PCI_IO_DEVICE *Temp; + + CurrentLink = gPciDevicePool.ForwardLink; + + while (CurrentLink && CurrentLink != &gPciDevicePool) { + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + + if (Temp->Handle == Controller) { + + RemoveEntryList (CurrentLink); + + DestroyPciDeviceTree (Temp); + + gBS->FreePool(Temp); + + return EFI_SUCCESS; + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +RegisterPciDevice ( + IN EFI_HANDLE Controller, + IN PCI_IO_DEVICE *PciIoDevice, + OUT EFI_HANDLE *Handle OPTIONAL + ) +/*++ + +Routine Description: + + This function registers the PCI IO device. It creates a handle for this PCI IO device + (if the handle does not exist), attaches appropriate protocols onto the handle, does + necessary initialization, and sets up parent/child relationship with its bus controller. + +Arguments: + + Controller - An EFI handle for the PCI bus controller. + PciIoDevice - A PCI_IO_DEVICE pointer to the PCI IO device to be registered. + Handle - A pointer to hold the EFI handle for the PCI IO device. + +Returns: + + EFI_SUCCESS - The PCI device is successfully registered. + Others - An error occurred when registering the PCI device. + +--*/ +{ + EFI_STATUS Status; + UINT8 PciExpressCapRegOffset; + + // + // Install the pciio protocol, device path protocol and + // Bus Specific Driver Override Protocol + // + + if (PciIoDevice->BusOverride) { + Status = gBS->InstallMultipleProtocolInterfaces ( + &PciIoDevice->Handle, + &gEfiDevicePathProtocolGuid, + PciIoDevice->DevicePath, + &gEfiPciIoProtocolGuid, + &PciIoDevice->PciIo, + &gEfiBusSpecificDriverOverrideProtocolGuid, + &PciIoDevice->PciDriverOverride, + NULL + ); + } else { + Status = gBS->InstallMultipleProtocolInterfaces ( + &PciIoDevice->Handle, + &gEfiDevicePathProtocolGuid, + PciIoDevice->DevicePath, + &gEfiPciIoProtocolGuid, + &PciIoDevice->PciIo, + NULL + ); + } + + if (EFI_ERROR (Status)) { + return Status; + } else { + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciRootBridgeIoProtocolGuid, + (VOID **)&(PciIoDevice->PciRootBridgeIo), + gPciBusDriverBinding.DriverBindingHandle, + PciIoDevice->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + if (Handle != NULL) { + *Handle = PciIoDevice->Handle; + } + + // + // Detect if PCI Express Device + // + PciExpressCapRegOffset = 0; + Status = LocateCapabilityRegBlock ( + PciIoDevice, + EFI_PCI_CAPABILITY_ID_PCIEXP, + &PciExpressCapRegOffset, + NULL + ); + if (!EFI_ERROR (Status)) { + PciIoDevice->IsPciExp = TRUE; + DEBUG ((EFI_D_ERROR, "PciExp - %x (B-%x, D-%x, F-%x)\n", PciIoDevice->IsPciExp, PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber)); + } + + // + // Indicate the pci device is registered + // + PciIoDevice->Registered = TRUE; + + return EFI_SUCCESS; +} + + +EFI_STATUS +DeRegisterPciDevice ( + IN EFI_HANDLE Controller, + IN EFI_HANDLE Handle + ) +/*++ + +Routine Description: + + This function is used to de-register the PCI device from the EFI, + That includes un-installing PciIo protocol from the specified PCI + device handle. + +Arguments: + + Controller - An efi handle. + Handle - An efi handle. + +Returns: + + None + +--*/ +{ + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + PCI_IO_DEVICE *Node; + LIST_ENTRY *CurrentLink; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + + Status = gBS->OpenProtocol ( + Handle, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + gPciBusDriverBinding.DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo); + + // + // If it is already de-registered + // + if (!PciIoDevice->Registered) { + return EFI_SUCCESS; + } + + // + // If it is PPB, first de-register its children + // + + if (IS_PCI_BRIDGE (&(PciIoDevice->Pci))) { + + CurrentLink = PciIoDevice->ChildList.ForwardLink; + + while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) { + Node = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + Status = DeRegisterPciDevice (Controller, Node->Handle); + + if (EFI_ERROR (Status)) { + return Status; + } + + CurrentLink = CurrentLink->ForwardLink; + } + } + + // + // First disconnect this device + // +// PciIoDevice->PciIo.Attributes(&(PciIoDevice->PciIo), +// EfiPciIoAttributeOperationDisable, +// EFI_PCI_DEVICE_ENABLE, +// NULL +// ); + + // + // Close the child handle + // + Status = gBS->CloseProtocol ( + Controller, + &gEfiPciRootBridgeIoProtocolGuid, + gPciBusDriverBinding.DriverBindingHandle, + Handle + ); + + // + // Un-install the device path protocol and pci io protocol + // + if (PciIoDevice->BusOverride) { + Status = gBS->UninstallMultipleProtocolInterfaces ( + Handle, + &gEfiDevicePathProtocolGuid, + PciIoDevice->DevicePath, + &gEfiPciIoProtocolGuid, + &PciIoDevice->PciIo, + &gEfiBusSpecificDriverOverrideProtocolGuid, + &PciIoDevice->PciDriverOverride, + NULL + ); + } else { + Status = gBS->UninstallMultipleProtocolInterfaces ( + Handle, + &gEfiDevicePathProtocolGuid, + PciIoDevice->DevicePath, + &gEfiPciIoProtocolGuid, + &PciIoDevice->PciIo, + NULL + ); + } + + if (EFI_ERROR (Status)) { + gBS->OpenProtocol ( + Controller, + &gEfiPciRootBridgeIoProtocolGuid, + (VOID **) &PciRootBridgeIo, + gPciBusDriverBinding.DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + return Status; + } + + // + // The Device Driver should disable this device after disconnect + // so the Pci Bus driver will not touch this device any more. + // Restore the register field to the original value + // + PciIoDevice->Registered = FALSE; + PciIoDevice->Handle = NULL; + } else { + + // + // Handle may be closed before + // + return EFI_SUCCESS; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EnableBridgeAttributes ( + IN PCI_IO_DEVICE *PciIoDevice + ) +{ + PCI_TYPE01 PciData; + + // + // NOTE: We should not set EFI_PCI_DEVICE_ENABLE for a bridge + // directly, because some legacy BIOS will NOT assign + // IO or Memory resource for a bridge who has no child + // device. So we add check IO or Memory here. + // + + PciIoDevice->PciIo.Pci.Read ( + &PciIoDevice->PciIo, + EfiPciIoWidthUint8, + 0, + sizeof (PciData), + &PciData + ); + + if ((((PciData.Bridge.IoBase & 0xF) == 0) && + (PciData.Bridge.IoBase != 0 || PciData.Bridge.IoLimit != 0)) || + (((PciData.Bridge.IoBase & 0xF) == 1) && + ((PciData.Bridge.IoBase & 0xF0) != 0 || (PciData.Bridge.IoLimit & 0xF0) != 0 || PciData.Bridge.IoBaseUpper16 != 0 || PciData.Bridge.IoLimitUpper16 != 0))) { + PciIoDevice->PciIo.Attributes( + &(PciIoDevice->PciIo), + EfiPciIoAttributeOperationEnable, + (EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER), + NULL + ); + } + if ((PciData.Bridge.MemoryBase & 0xFFF0) != 0 || (PciData.Bridge.MemoryLimit & 0xFFF0) != 0) { + PciIoDevice->PciIo.Attributes( + &(PciIoDevice->PciIo), + EfiPciIoAttributeOperationEnable, + (EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER), + NULL + ); + } + if ((((PciData.Bridge.PrefetchableMemoryBase & 0xF) == 0) && + (PciData.Bridge.PrefetchableMemoryBase != 0 || PciData.Bridge.PrefetchableMemoryLimit != 0)) || + (((PciData.Bridge.PrefetchableMemoryBase & 0xF) == 1) && + ((PciData.Bridge.PrefetchableMemoryBase & 0xFFF0) != 0 || (PciData.Bridge.PrefetchableMemoryLimit & 0xFFF0) != 0 || PciData.Bridge.PrefetchableBaseUpper32 != 0 || PciData.Bridge.PrefetchableLimitUpper32 != 0))) { + PciIoDevice->PciIo.Attributes( + &(PciIoDevice->PciIo), + EfiPciIoAttributeOperationEnable, + (EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER), + NULL + ); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +StartPciDevicesOnBridge ( + IN EFI_HANDLE Controller, + IN PCI_IO_DEVICE *RootBridge, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + Start to manage the PCI device on specified the root bridge or PCI-PCI Bridge + +Arguments: + + Controller - An efi handle. + RootBridge - A pointer to the PCI_IO_DEVICE. + RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL. + NumberOfChildren - Children number. + ChildHandleBuffer - A pointer to the child handle buffer. + +Returns: + + None + +--*/ +{ + PCI_IO_DEVICE *Temp; + PCI_IO_DEVICE *PciIoDevice; + EFI_DEV_PATH_PTR Node; + EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath; + EFI_STATUS Status; + LIST_ENTRY *CurrentLink; + + CurrentLink = RootBridge->ChildList.ForwardLink; + + while (CurrentLink && CurrentLink != &RootBridge->ChildList) { + + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + if (RemainingDevicePath != NULL) { + + Node.DevPath = RemainingDevicePath; + + if (Node.Pci->Device != Temp->DeviceNumber || + Node.Pci->Function != Temp->FunctionNumber) { + CurrentLink = CurrentLink->ForwardLink; + continue; + } + + // + // Check if the device has been assigned with required resource + // + if (!Temp->Allocated) { + return EFI_NOT_READY; + } + + // + // Check if the current node has been registered before + // If it is not, register it + // + if (!Temp->Registered) { + PciIoDevice = Temp; + + Status = RegisterPciDevice ( + Controller, + PciIoDevice, + NULL + ); + + } + + // + // Get the next device path + // + CurrentDevicePath = NextDevicePathNode (RemainingDevicePath); + if (IsDevicePathEnd (CurrentDevicePath)) { + return EFI_SUCCESS; + } + + // + // If it is a PPB + // + if (IS_PCI_BRIDGE (&(Temp->Pci))) { + Status = StartPciDevicesOnBridge ( + Controller, + Temp, + CurrentDevicePath + ); + EnableBridgeAttributes (Temp); + + return Status; + } else { + + // + // Currently, the PCI bus driver only support PCI-PCI bridge + // + return EFI_UNSUPPORTED; + } + + } else { + + // + // If remaining device path is NULL, + // try to enable all the pci devices under this bridge + // + + if (!Temp->Registered && Temp->Allocated) { + + PciIoDevice = Temp; + + Status = RegisterPciDevice ( + Controller, + PciIoDevice, + NULL + ); + + } + + if (IS_PCI_BRIDGE (&(Temp->Pci))) { + Status = StartPciDevicesOnBridge ( + Controller, + Temp, + RemainingDevicePath + ); + EnableBridgeAttributes (Temp); + } + + CurrentLink = CurrentLink->ForwardLink; + continue; + } + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +StartPciDevices ( + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + Start to manage the PCI device according to RemainingDevicePath + If RemainingDevicePath == NULL, the PCI bus driver will start + to manage all the PCI devices it found previously + +Arguments: + Controller - An efi handle. + RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL. + +Returns: + + None + +--*/ +{ + EFI_DEV_PATH_PTR Node; + PCI_IO_DEVICE *RootBridge; + LIST_ENTRY *CurrentLink; + + if (RemainingDevicePath != NULL) { + + // + // Check if the RemainingDevicePath is valid + // + Node.DevPath = RemainingDevicePath; + if (Node.DevPath->Type != HARDWARE_DEVICE_PATH || + Node.DevPath->SubType != HW_PCI_DP || + DevicePathNodeLength (Node.DevPath) != sizeof (PCI_DEVICE_PATH) + ) { + return EFI_UNSUPPORTED; + } + } + + CurrentLink = gPciDevicePool.ForwardLink; + + while (CurrentLink && CurrentLink != &gPciDevicePool) { + + RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + // + // Locate the right root bridge to start + // + if (RootBridge->Handle == Controller) { + StartPciDevicesOnBridge ( + Controller, + RootBridge, + RemainingDevicePath + ); + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return EFI_SUCCESS; +} + +PCI_IO_DEVICE * +CreateRootBridge ( + IN EFI_HANDLE RootBridgeHandle + ) +/*++ + +Routine Description: + + +Arguments: + RootBridgeHandle - An efi handle. + +Returns: + + None + +--*/ +{ + + EFI_STATUS Status; + PCI_IO_DEVICE *Dev; + + Dev = NULL; + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (PCI_IO_DEVICE), + (VOID **) &Dev + ); + + if (EFI_ERROR (Status)) { + return NULL; + } + + ZeroMem (Dev, sizeof (PCI_IO_DEVICE)); + Dev->Signature = PCI_IO_DEVICE_SIGNATURE; + Dev->Handle = RootBridgeHandle; + InitializeListHead (&Dev->ChildList); + + return Dev; +} + +PCI_IO_DEVICE * +GetRootBridgeByHandle ( + EFI_HANDLE RootBridgeHandle + ) +/*++ + +Routine Description: + + +Arguments: + + RootBridgeHandle - An efi handle. + +Returns: + + None + +--*/ +{ + PCI_IO_DEVICE *RootBridgeDev; + LIST_ENTRY *CurrentLink; + + CurrentLink = gPciDevicePool.ForwardLink; + + while (CurrentLink && CurrentLink != &gPciDevicePool) { + + RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + if (RootBridgeDev->Handle == RootBridgeHandle) { + return RootBridgeDev; + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return NULL; +} + +BOOLEAN +RootBridgeExisted ( + IN EFI_HANDLE RootBridgeHandle + ) +/*++ + +Routine Description: + + This function searches if RootBridgeHandle has already existed + in current device pool. + + If so, it means the given root bridge has been already enumerated. + +Arguments: + + RootBridgeHandle - An efi handle. + +Returns: + + None + +--*/ +{ + PCI_IO_DEVICE *Bridge; + + Bridge = GetRootBridgeByHandle (RootBridgeHandle); + + if (Bridge != NULL) { + return TRUE; + } + + return FALSE; +} + +BOOLEAN +PciDeviceExisted ( + IN PCI_IO_DEVICE *Bridge, + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + + Bridge - A pointer to the PCI_IO_DEVICE. + PciIoDevice - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +{ + + PCI_IO_DEVICE *Temp; + LIST_ENTRY *CurrentLink; + + CurrentLink = Bridge->ChildList.ForwardLink; + + while (CurrentLink && CurrentLink != &Bridge->ChildList) { + + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + + if (Temp == PciIoDevice) { + return TRUE; + } + + if (!IsListEmpty (&Temp->ChildList)) { + if (PciDeviceExisted (Temp, PciIoDevice)) { + return TRUE; + } + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return FALSE; +} + +PCI_IO_DEVICE * +ActiveVGADeviceOnTheSameSegment ( + IN PCI_IO_DEVICE *VgaDevice + ) +/*++ + +Routine Description: + +Arguments: + + VgaDevice - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +{ + LIST_ENTRY *CurrentLink; + PCI_IO_DEVICE *Temp; + + CurrentLink = gPciDevicePool.ForwardLink; + + while (CurrentLink && CurrentLink != &gPciDevicePool) { + + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + + if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) { + + Temp = ActiveVGADeviceOnTheRootBridge (Temp); + + if (Temp != NULL) { + return Temp; + } + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return NULL; +} + +PCI_IO_DEVICE * +ActiveVGADeviceOnTheRootBridge ( + IN PCI_IO_DEVICE *RootBridge + ) +/*++ + +Routine Description: + +Arguments: + + RootBridge - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +{ + LIST_ENTRY *CurrentLink; + PCI_IO_DEVICE *Temp; + + CurrentLink = RootBridge->ChildList.ForwardLink; + + while (CurrentLink && CurrentLink != &RootBridge->ChildList) { + + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + + if (IS_PCI_VGA(&Temp->Pci) && + (Temp->Attributes & + (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | + EFI_PCI_IO_ATTRIBUTE_VGA_IO | + EFI_PCI_IO_ATTRIBUTE_VGA_IO_16))) { + return Temp; + } + + if (IS_PCI_BRIDGE (&Temp->Pci)) { + + Temp = ActiveVGADeviceOnTheRootBridge (Temp); + + if (Temp != NULL) { + return Temp; + } + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return NULL; +} diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciDeviceSupport.h b/CorebootModulePkg/PciBusNoEnumerationDxe/PciDeviceSupport.h new file mode 100644 index 0000000000..07fd54bced --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciDeviceSupport.h @@ -0,0 +1,324 @@ +/*++ + +Copyright (c) 2005 - 2006, 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: + + PciDeviceSupport.h + +Abstract: + + + +Revision History + +--*/ + +#ifndef _EFI_PCI_DEVICE_SUPPORT_H +#define _EFI_PCI_DEVICE_SUPPORT_H + +EFI_STATUS +InitializePciDevicePool ( + VOID + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + None + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +InsertPciDevice ( + PCI_IO_DEVICE *Bridge, + PCI_IO_DEVICE *PciDeviceNode + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + PciDeviceNode - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DestroyPciDeviceTree ( + IN PCI_IO_DEVICE *Bridge + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +DestroyRootBridgeByHandle ( + EFI_HANDLE Controller + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Controller - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +RegisterPciDevice ( + IN EFI_HANDLE Controller, + IN PCI_IO_DEVICE *PciIoDevice, + OUT EFI_HANDLE *Handle OPTIONAL + ) +/*++ + +Routine Description: + + This function registers the PCI IO device. It creates a handle for this PCI IO device + (if the handle does not exist), attaches appropriate protocols onto the handle, does + necessary initialization, and sets up parent/child relationship with its bus controller. + +Arguments: + + Controller - An EFI handle for the PCI bus controller. + PciIoDevice - A PCI_IO_DEVICE pointer to the PCI IO device to be registered. + Handle - A pointer to hold the EFI handle for the PCI IO device. + +Returns: + + EFI_SUCCESS - The PCI device is successfully registered. + Others - An error occurred when registering the PCI device. + +--*/ +; + +EFI_STATUS +DeRegisterPciDevice ( + IN EFI_HANDLE Controller, + IN EFI_HANDLE Handle + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Controller - TODO: add argument description + Handle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +StartPciDevices ( + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Controller - TODO: add argument description + RemainingDevicePath - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +PCI_IO_DEVICE * +CreateRootBridge ( + IN EFI_HANDLE RootBridgeHandle + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + RootBridgeHandle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +PCI_IO_DEVICE * +GetRootBridgeByHandle ( + EFI_HANDLE RootBridgeHandle + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + RootBridgeHandle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +InsertRootBridge ( + PCI_IO_DEVICE *RootBridge +); + +EFI_STATUS +DestroyRootBridge ( + IN PCI_IO_DEVICE *RootBridge +); + +BOOLEAN +RootBridgeExisted ( + IN EFI_HANDLE RootBridgeHandle + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + RootBridgeHandle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +BOOLEAN +PciDeviceExisted ( + IN PCI_IO_DEVICE *Bridge, + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +PCI_IO_DEVICE * +ActiveVGADeviceOnTheSameSegment ( + IN PCI_IO_DEVICE *VgaDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + VgaDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +PCI_IO_DEVICE * +ActiveVGADeviceOnTheRootBridge ( + IN PCI_IO_DEVICE *RootBridge + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + RootBridge - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; +#endif diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciDriverOverride.c b/CorebootModulePkg/PciBusNoEnumerationDxe/PciDriverOverride.c new file mode 100644 index 0000000000..6e936accd6 --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciDriverOverride.c @@ -0,0 +1,176 @@ +/*++ + +Copyright (c) 2005 - 2007, 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: + + PciDriverOverride.c + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#include "PciBus.h" + +EFI_STATUS +EFIAPI +GetDriver( + IN EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *This, + IN OUT EFI_HANDLE *DriverImageHandle + ); + + + +EFI_STATUS +InitializePciDriverOverrideInstance ( + PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + Initializes a PCI Driver Override Instance + +Arguments: + +Returns: + + None + +--*/ + +{ + PciIoDevice->PciDriverOverride.GetDriver = GetDriver; + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +GetDriver ( + IN EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *This, + IN OUT EFI_HANDLE *DriverImageHandle + ) +/*++ + +Routine Description: + + Get a overriding driver image + +Arguments: + +Returns: + + None + +--*/ +{ + PCI_IO_DEVICE *PciIoDevice; + LIST_ENTRY *CurrentLink; + PCI_DRIVER_OVERRIDE_LIST *Node; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_DRIVER_OVERRIDE_THIS (This); + + CurrentLink = PciIoDevice->OptionRomDriverList.ForwardLink; + + while (CurrentLink && CurrentLink != &PciIoDevice->OptionRomDriverList) { + + Node = DRIVER_OVERRIDE_FROM_LINK (CurrentLink); + + if (*DriverImageHandle == NULL) { + + *DriverImageHandle = Node->DriverImageHandle; + return EFI_SUCCESS; + } + + if (*DriverImageHandle == Node->DriverImageHandle) { + + if (CurrentLink->ForwardLink == &PciIoDevice->OptionRomDriverList || + CurrentLink->ForwardLink == NULL) { + return EFI_NOT_FOUND; + } + + // + // Get next node + // + Node = DRIVER_OVERRIDE_FROM_LINK (CurrentLink->ForwardLink); + *DriverImageHandle = Node->DriverImageHandle; + return EFI_SUCCESS; + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return EFI_INVALID_PARAMETER; +} + +EFI_STATUS +AddDriver ( + IN PCI_IO_DEVICE *PciIoDevice, + IN EFI_HANDLE DriverImageHandle + ) +/*++ + +Routine Description: + + Add a overriding driver image + +Arguments: + +Returns: + + None + +--*/ + +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + PCI_DRIVER_OVERRIDE_LIST *Node; + + Status = gBS->HandleProtocol (DriverImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage); + if (EFI_ERROR (Status)) { + return Status; + } + + Node = AllocatePool (sizeof (PCI_DRIVER_OVERRIDE_LIST)); + if (Node == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Node->Signature = DRIVER_OVERRIDE_SIGNATURE; + Node->DriverImageHandle = DriverImageHandle; + + InsertTailList (&PciIoDevice->OptionRomDriverList, &(Node->Link)); + + PciIoDevice->BusOverride = TRUE; + + + ImageContext.Handle = LoadedImage->ImageBase; + ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; + + // + // Get information about the image + // + Status = PeCoffLoaderGetImageInfo (&ImageContext); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + + if (ImageContext.Machine != EFI_IMAGE_MACHINE_EBC) { + return EFI_SUCCESS; + } + + return EFI_SUCCESS; +} diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciDriverOverride.h b/CorebootModulePkg/PciBusNoEnumerationDxe/PciDriverOverride.h new file mode 100644 index 0000000000..5fbba2e304 --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciDriverOverride.h @@ -0,0 +1,110 @@ +/*++ + +Copyright (c) 2005 - 2006, 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: + + PciDriverOverride.h + +Abstract: + + + +Revision History + +--*/ + +#ifndef _EFI_PCI_DRIVER_OVERRRIDE_H +#define _EFI_PCI_DRIVER_OVERRRIDE_H + +#include "PciBus.h" + +#define DRIVER_OVERRIDE_SIGNATURE SIGNATURE_32 ('d', 'r', 'o', 'v') + +typedef struct { + UINT32 Signature; + LIST_ENTRY Link; + EFI_HANDLE DriverImageHandle; +} PCI_DRIVER_OVERRIDE_LIST; + + +#define DRIVER_OVERRIDE_FROM_LINK(a) \ + CR (a, PCI_DRIVER_OVERRIDE_LIST, Link, DRIVER_OVERRIDE_SIGNATURE) + + +EFI_STATUS +InitializePciDriverOverrideInstance ( + PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +AddDriver ( + IN PCI_IO_DEVICE *PciIoDevice, + IN EFI_HANDLE DriverImageHandle + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + DriverImageHandle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +EFIAPI +GetDriver ( + IN EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL *This, + IN OUT EFI_HANDLE *DriverImageHandle + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + DriverImageHandle - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciEnumerator.c b/CorebootModulePkg/PciBusNoEnumerationDxe/PciEnumerator.c new file mode 100644 index 0000000000..729c567c40 --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciEnumerator.c @@ -0,0 +1,57 @@ +/*++ + +Copyright (c) 2005 - 2006, 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: + + PciEnumerator.c + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#include "PciBus.h" + +EFI_STATUS +PciEnumerator ( + IN EFI_HANDLE Controller + ) +/*++ + +Routine Description: + + This routine is used to enumerate entire pci bus system + in a given platform + +Arguments: + +Returns: + + None + +--*/ +{ + // + // This PCI bus driver depends on the legacy BIOS + // to do the resource allocation + // + gFullEnumeration = FALSE; + + return PciEnumeratorLight (Controller) ; + +} + + + + diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciEnumerator.h b/CorebootModulePkg/PciBusNoEnumerationDxe/PciEnumerator.h new file mode 100644 index 0000000000..09c9d69612 --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciEnumerator.h @@ -0,0 +1,47 @@ +/*++ + +Copyright (c) 2005 - 2006, 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: + + PciEnumerator.h + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#ifndef _EFI_PCI_ENUMERATOR_H +#define _EFI_PCI_ENUMERATOR_H + +EFI_STATUS +PciEnumerator ( + IN EFI_HANDLE Controller + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Controller - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; +#endif diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciEnumeratorSupport.c b/CorebootModulePkg/PciBusNoEnumerationDxe/PciEnumeratorSupport.c new file mode 100644 index 0000000000..27311fd1e2 --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciEnumeratorSupport.c @@ -0,0 +1,1385 @@ +/*++ + +Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR> +(C) Copyright 2015 Hewlett Packard Enterprise Development LP<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: + + PciEnumeratorSupport.c + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#include "PciBus.h" + +EFI_STATUS +InitializePPB ( + IN PCI_IO_DEVICE *PciIoDevice +); + +EFI_STATUS +InitializeP2C ( + IN PCI_IO_DEVICE *PciIoDevice +); + +PCI_IO_DEVICE* +CreatePciIoDevice ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + IN PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func +); + + +PCI_IO_DEVICE* +GatherP2CInfo ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + IN PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func +); + +UINTN +PciParseBar ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINTN Offset, + IN UINTN BarIndex +); + + +EFI_STATUS +PciSearchDevice ( + IN PCI_IO_DEVICE *Bridge, + PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func, + PCI_IO_DEVICE **PciDevice +); + + +EFI_STATUS +DetermineDeviceAttribute ( + IN PCI_IO_DEVICE *PciIoDevice +); + +EFI_STATUS +BarExisted ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINTN Offset, + OUT UINT32 *BarLengthValue, + OUT UINT32 *OriginalBarValue + ); + + + +EFI_DEVICE_PATH_PROTOCOL* +CreatePciDevicePath( + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, + IN PCI_IO_DEVICE *PciIoDevice +); + +PCI_IO_DEVICE* +GatherDeviceInfo ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + IN PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func +); + +PCI_IO_DEVICE* +GatherPPBInfo ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + IN PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func +); + +EFI_STATUS +PciDevicePresent ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func + ) +/*++ + +Routine Description: + + This routine is used to check whether the pci device is present + +Arguments: + +Returns: + + None + +--*/ +{ + UINT64 Address; + EFI_STATUS Status; + + // + // Create PCI address map in terms of Bus, Device and Func + // + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0); + + // + // Read the Vendor Id register + // + Status = PciRootBridgeIo->Pci.Read ( + PciRootBridgeIo, + EfiPciWidthUint32, + Address, + 1, + Pci + ); + + if (!EFI_ERROR (Status) && (Pci->Hdr).VendorId != 0xffff) { + + // + // Read the entire config header for the device + // + + Status = PciRootBridgeIo->Pci.Read ( + PciRootBridgeIo, + EfiPciWidthUint32, + Address, + sizeof (PCI_TYPE00) / sizeof (UINT32), + Pci + ); + + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +PciPciDeviceInfoCollector ( + IN PCI_IO_DEVICE *Bridge, + UINT8 StartBusNumber + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + PCI_TYPE00 Pci; + UINT8 Device; + UINT8 Func; + UINT8 SecBus; + PCI_IO_DEVICE *PciIoDevice; + EFI_PCI_IO_PROTOCOL *PciIo; + + Status = EFI_SUCCESS; + SecBus = 0; + PciIoDevice = NULL; + + for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) { + + for (Func = 0; Func <= PCI_MAX_FUNC; Func++) { + + // + // Check to see whether PCI device is present + // + + Status = PciDevicePresent ( + Bridge->PciRootBridgeIo, + &Pci, + (UINT8) StartBusNumber, + (UINT8) Device, + (UINT8) Func + ); + + if (EFI_ERROR (Status) && Func == 0) { + // + // go to next device if there is no Function 0 + // + break; + } + + if (!EFI_ERROR (Status)) { + + // + // Collect all the information about the PCI device discovered + // + Status = PciSearchDevice ( + Bridge, + &Pci, + (UINT8) StartBusNumber, + Device, + Func, + &PciIoDevice + ); + + // + // Recursively scan PCI busses on the other side of PCI-PCI bridges + // + // + + if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) { + + // + // If it is PPB, we need to get the secondary bus to continue the enumeration + // + PciIo = &(PciIoDevice->PciIo); + + Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x19, 1, &SecBus); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // If the PCI bridge is initialized then enumerate the next level bus + // + if (SecBus != 0) { + Status = PciPciDeviceInfoCollector ( + PciIoDevice, + (UINT8) (SecBus) + ); + } + } + + if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) { + + // + // Skip sub functions, this is not a multi function device + // + Func = PCI_MAX_FUNC; + } + } + + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PciSearchDevice ( + IN PCI_IO_DEVICE *Bridge, + IN PCI_TYPE00 *Pci, + IN UINT8 Bus, + IN UINT8 Device, + IN UINT8 Func, + OUT PCI_IO_DEVICE **PciDevice + ) +/*++ + +Routine Description: + + Search required device. + +Arguments: + + Bridge - A pointer to the PCI_IO_DEVICE. + Pci - A pointer to the PCI_TYPE00. + Bus - Bus number. + Device - Device number. + Func - Function number. + PciDevice - The Required pci device. + +Returns: + + Status code. + +--*/ +{ + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = NULL; + + if (!IS_PCI_BRIDGE (Pci)) { + + if (IS_CARDBUS_BRIDGE (Pci)) { + PciIoDevice = GatherP2CInfo ( + Bridge->PciRootBridgeIo, + Pci, + Bus, + Device, + Func + ); + if ((PciIoDevice != NULL) && (gFullEnumeration == TRUE)) { + InitializeP2C (PciIoDevice); + } + } else { + + // + // Create private data for Pci Device + // + PciIoDevice = GatherDeviceInfo ( + Bridge->PciRootBridgeIo, + Pci, + Bus, + Device, + Func + ); + + } + + } else { + + // + // Create private data for PPB + // + PciIoDevice = GatherPPBInfo ( + Bridge->PciRootBridgeIo, + Pci, + Bus, + Device, + Func + ); + + // + // Special initialization for PPB including making the PPB quiet + // + if ((PciIoDevice != NULL) && (gFullEnumeration == TRUE)) { + InitializePPB (PciIoDevice); + } + } + + if (!PciIoDevice) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Create a device path for this PCI device and store it into its private data + // + CreatePciDevicePath( + Bridge->DevicePath, + PciIoDevice + ); + + // + // Detect this function has option rom + // + if (gFullEnumeration) { + + if (!IS_CARDBUS_BRIDGE (Pci)) { + + GetOpRomInfo (PciIoDevice); + + } + + ResetPowerManagementFeature (PciIoDevice); + + } + else { + PciRomGetRomResourceFromPciOptionRomTable ( + &gPciBusDriverBinding, + PciIoDevice->PciRootBridgeIo, + PciIoDevice + ); + } + + + // + // Insert it into a global tree for future reference + // + InsertPciDevice (Bridge, PciIoDevice); + + // + // Determine PCI device attributes + // + DetermineDeviceAttribute (PciIoDevice); + + if (PciDevice != NULL) { + *PciDevice = PciIoDevice; + } + + return EFI_SUCCESS; +} + +PCI_IO_DEVICE * +GatherDeviceInfo ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + IN PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + UINTN Offset; + UINTN BarIndex; + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = CreatePciIoDevice ( + PciRootBridgeIo, + Pci, + Bus, + Device, + Func + ); + + if (!PciIoDevice) { + return NULL; + } + + // + // If it is a full enumeration, disconnect the device in advance + // + if (gFullEnumeration) { + + PciDisableCommandRegister (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED); + + } + + // + // Start to parse the bars + // + for (Offset = 0x10, BarIndex = 0; Offset <= 0x24; BarIndex++) { + Offset = PciParseBar (PciIoDevice, Offset, BarIndex); + } + + return PciIoDevice; +} + +PCI_IO_DEVICE * +GatherPPBInfo ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + IN PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + PCI_IO_DEVICE *PciIoDevice; + EFI_STATUS Status; + UINT8 Value; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT8 Temp; + + PciIoDevice = CreatePciIoDevice ( + PciRootBridgeIo, + Pci, + Bus, + Device, + Func + ); + + if (!PciIoDevice) { + return NULL; + } + + if (gFullEnumeration) { + PciDisableCommandRegister (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED); + + // + // Initalize the bridge control register + // + PciDisableBridgeControlRegister (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED); + } + + PciIo = &PciIoDevice->PciIo; + + // + // Test whether it support 32 decode or not + // + PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp); + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne); + PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value); + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp); + + if (Value) { + if (Value & 0x01) { + PciIoDevice->Decodes |= EFI_BRIDGE_IO32_DECODE_SUPPORTED; + } else { + PciIoDevice->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED; + } + } + + Status = BarExisted ( + PciIoDevice, + 0x24, + NULL, + NULL + ); + + // + // test if it supports 64 memory or not + // + if (!EFI_ERROR (Status)) { + + Status = BarExisted ( + PciIoDevice, + 0x28, + NULL, + NULL + ); + + if (!EFI_ERROR (Status)) { + PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED; + PciIoDevice->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED; + } else { + PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED; + } + } + + // + // Memory 32 code is required for ppb + // + PciIoDevice->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED; + + return PciIoDevice; +} + +PCI_IO_DEVICE * +GatherP2CInfo ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + IN PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = CreatePciIoDevice ( + PciRootBridgeIo, + Pci, + Bus, + Device, + Func + ); + + if (!PciIoDevice) { + return NULL; + } + + if (gFullEnumeration) { + PciDisableCommandRegister (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED); + + // + // Initalize the bridge control register + // + PciDisableBridgeControlRegister (PciIoDevice, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED); + + } + // + // P2C only has one bar that is in 0x10 + // + PciParseBar(PciIoDevice, 0x10, 0); + + PciIoDevice->Decodes = EFI_BRIDGE_MEM32_DECODE_SUPPORTED | + EFI_BRIDGE_PMEM32_DECODE_SUPPORTED | + EFI_BRIDGE_IO32_DECODE_SUPPORTED; + + return PciIoDevice; +} + +EFI_DEVICE_PATH_PROTOCOL * +CreatePciDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + + PCI_DEVICE_PATH PciNode; + + // + // Create PCI device path + // + PciNode.Header.Type = HARDWARE_DEVICE_PATH; + PciNode.Header.SubType = HW_PCI_DP; + SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode)); + + PciNode.Device = PciIoDevice->DeviceNumber; + PciNode.Function = PciIoDevice->FunctionNumber; + PciIoDevice->DevicePath = AppendDevicePathNode (ParentDevicePath, &PciNode.Header); + + return PciIoDevice->DevicePath; +} + +EFI_STATUS +BarExisted ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINTN Offset, + OUT UINT32 *BarLengthValue, + OUT UINT32 *OriginalBarValue + ) +/*++ + +Routine Description: + + Check the bar is existed or not. + +Arguments: + + PciIoDevice - A pointer to the PCI_IO_DEVICE. + Offset - The offset. + BarLengthValue - The bar length value. + OriginalBarValue - The original bar value. + +Returns: + + EFI_NOT_FOUND - The bar don't exist. + EFI_SUCCESS - The bar exist. + +--*/ +{ + EFI_PCI_IO_PROTOCOL *PciIo; + UINT32 OriginalValue; + UINT32 Value; + EFI_TPL OldTpl; + + PciIo = &PciIoDevice->PciIo; + + // + // Preserve the original value + // + + PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue); + + // + // Raise TPL to high level to disable timer interrupt while the BAR is probed + // + OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); + + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &gAllOne); + PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &Value); + + // + // Write back the original value + // + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue); + + // + // Restore TPL to its original level + // + gBS->RestoreTPL (OldTpl); + + if (BarLengthValue != NULL) { + *BarLengthValue = Value; + } + + if (OriginalBarValue != NULL) { + *OriginalBarValue = OriginalValue; + } + + if (Value == 0) { + return EFI_NOT_FOUND; + } else { + return EFI_SUCCESS; + } +} + + +EFI_STATUS +DetermineDeviceAttribute ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + Determine the related attributes of all devices under a Root Bridge + +Arguments: + +Returns: + + None + +--*/ +{ + UINT16 Command; + UINT16 BridgeControl; + + Command = 0; + + PciIoDevice->Supports |= EFI_PCI_DEVICE_ENABLE; + PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE; + + if (IS_PCI_VGA (&(PciIoDevice->Pci))){ + + // + // If the device is VGA, VGA related Attributes are supported + // + PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO ; + PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY ; + PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_VGA_IO ; + } + + if(IS_ISA_BRIDGE(&(PciIoDevice->Pci)) || IS_INTEL_ISA_BRIDGE(&(PciIoDevice->Pci))) { + // + // If the devie is a ISA Bridge, set the two attributes + // + PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO; + PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_ISA_IO; + } + + if (IS_PCI_GFX (&(PciIoDevice->Pci))) { + + // + // If the device is GFX, then only set the EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO + // attribute + // + PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO ; + } + + + // + // If the device is IDE, IDE related attributes are supported + // + if (IS_PCI_IDE (&(PciIoDevice->Pci))) { + PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO ; + PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO ; + } + + PciReadCommandRegister(PciIoDevice, &Command); + + + if (Command & EFI_PCI_COMMAND_IO_SPACE) { + PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_IO; + } + + if (Command & EFI_PCI_COMMAND_MEMORY_SPACE) { + PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY; + } + + if (Command & EFI_PCI_COMMAND_BUS_MASTER) { + PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER; + } + + if (IS_PCI_BRIDGE (&(PciIoDevice->Pci)) || + IS_CARDBUS_BRIDGE (&(PciIoDevice->Pci))){ + + // + // If it is a PPB, read the Bridge Control Register to determine + // the relevant attributes + // + BridgeControl = 0; + PciReadBridgeControlRegister(PciIoDevice, &BridgeControl); + + // + // Determine whether the ISA bit is set + // If ISA Enable on Bridge is set, the PPB + // will block forwarding 0x100-0x3ff for each 1KB in the + // first 64KB I/O range. + // + if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) != 0) { + PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO; + } + + // + // Determine whether the VGA bit is set + // If it is set, the bridge is set to decode VGA memory range + // and palette register range + // + if (IS_PCI_VGA (&(PciIoDevice->Pci)) &&BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) { + PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO; + PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY; + PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO; + } + + // + // if the palette snoop bit is set, then the brige is set to + // decode palette IO write + // + if (Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) { + PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO; + } + } + + return EFI_SUCCESS; +} + +UINTN +PciParseBar ( + IN PCI_IO_DEVICE *PciIoDevice, + IN UINTN Offset, + IN UINTN BarIndex + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + UINT32 Value; + UINT32 OriginalValue; + UINT32 Mask; + EFI_STATUS Status; + + OriginalValue = 0; + Value = 0; + + Status = BarExisted ( + PciIoDevice, + Offset, + &Value, + &OriginalValue + ); + + if (EFI_ERROR (Status)) { + PciIoDevice->PciBar[BarIndex].BaseAddress = 0; + PciIoDevice->PciBar[BarIndex].Length = 0; + PciIoDevice->PciBar[BarIndex].Alignment = 0; + + // + // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway + // + PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset; + return Offset + 4; + } + + PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset; + if (Value & 0x01) { + // + // Device I/Os + // + Mask = 0xfffffffc; + + if (Value & 0xFFFF0000) { + // + // It is a IO32 bar + // + PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32; + PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1); + PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; + + } else { + // + // It is a IO16 bar + // + PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16; + PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1); + PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; + + } + // + // Workaround. Some platforms inplement IO bar with 0 length + // Need to treat it as no-bar + // + if (PciIoDevice->PciBar[BarIndex].Length == 0) { + PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown; + } + + PciIoDevice->PciBar[BarIndex].Prefetchable = FALSE; + PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask; + + } else { + + Mask = 0xfffffff0; + + PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask; + + switch (Value & 0x07) { + + // + //memory space; anywhere in 32 bit address space + // + case 0x00: + if (Value & 0x08) { + PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32; + } else { + PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32; + } + + PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1; + PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; + + break; + + // + // memory space; anywhere in 64 bit address space + // + case 0x04: + if (Value & 0x08) { + PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64; + } else { + PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64; + } + + // + // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar + // is regarded as an extension for the first bar. As a result + // the sizing will be conducted on combined 64 bit value + // Here just store the masked first 32bit value for future size + // calculation + // + PciIoDevice->PciBar[BarIndex].Length = Value & Mask; + PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; + + // + // Increment the offset to point to next DWORD + // + Offset += 4; + + Status = BarExisted ( + PciIoDevice, + Offset, + &Value, + &OriginalValue + ); + + if (EFI_ERROR (Status)) { + return Offset + 4; + } + + // + // Fix the length to support some spefic 64 bit BAR + // + Value |= ((UINT32)(-1) << HighBitSet32 (Value)); + + // + // Calculate the size of 64bit bar + // + PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32); + + PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32); + PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1; + PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; + + break; + + // + // reserved + // + default: + PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown; + PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1; + PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; + + break; + } + } + + // + // Check the length again so as to keep compatible with some special bars + // + if (PciIoDevice->PciBar[BarIndex].Length == 0) { + PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown; + PciIoDevice->PciBar[BarIndex].BaseAddress = 0; + PciIoDevice->PciBar[BarIndex].Alignment = 0; + } + + // + // Increment number of bar + // + return Offset + 4; +} + +EFI_STATUS +InitializePPB ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_PCI_IO_PROTOCOL *PciIo; + + PciIo = &(PciIoDevice->PciIo); + + // + // Put all the resource apertures including IO16 + // Io32, pMem32, pMem64 to quiescent state + // Resource base all ones, Resource limit all zeros + // + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne); + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero); + + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne); + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero); + + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne); + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero); + + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne); + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero); + + // + // don't support use io32 as for now + // + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne); + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero); + + return EFI_SUCCESS; +} + +EFI_STATUS +InitializeP2C ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_PCI_IO_PROTOCOL *PciIo; + + PciIo = &(PciIoDevice->PciIo); + + // + // Put all the resource apertures including IO16 + // Io32, pMem32, pMem64 to quiescent state( + // Resource base all ones, Resource limit all zeros + // + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne); + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero); + + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne); + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero); + + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne); + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero); + + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne); + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero); + + return EFI_SUCCESS; +} + +PCI_IO_DEVICE * +CreatePciIoDevice ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + IN PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = NULL; + + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (PCI_IO_DEVICE), + (VOID **) &PciIoDevice + ); + + if (EFI_ERROR (Status)) { + return NULL; + } + + ZeroMem (PciIoDevice, sizeof (PCI_IO_DEVICE)); + + PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE; + PciIoDevice->Handle = NULL; + PciIoDevice->PciRootBridgeIo = PciRootBridgeIo; + PciIoDevice->DevicePath = NULL; + PciIoDevice->BusNumber = Bus; + PciIoDevice->DeviceNumber = Device; + PciIoDevice->FunctionNumber = Func; + PciIoDevice->Decodes = 0; + if (gFullEnumeration) { + PciIoDevice->Allocated = FALSE; + } else { + PciIoDevice->Allocated = TRUE; + } + + PciIoDevice->Attributes = 0; + PciIoDevice->Supports = 0; + PciIoDevice->BusOverride = FALSE; + PciIoDevice->IsPciExp = FALSE; + + CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01)); + + // + // Initialize the PCI I/O instance structure + // + + Status = InitializePciIoInstance (PciIoDevice); + Status = InitializePciDriverOverrideInstance (PciIoDevice); + + if (EFI_ERROR (Status)) { + gBS->FreePool (PciIoDevice); + return NULL; + } + + // + // Initialize the reserved resource list + // + InitializeListHead (&PciIoDevice->ReservedResourceList); + + // + // Initialize the driver list + // + InitializeListHead (&PciIoDevice->OptionRomDriverList); + + // + // Initialize the child list + // + InitializeListHead (&PciIoDevice->ChildList); + + return PciIoDevice; +} + +EFI_STATUS +PciEnumeratorLight ( + IN EFI_HANDLE Controller + ) +/*++ + +Routine Description: + + This routine is used to enumerate entire pci bus system + in a given platform + +Arguments: + +Returns: + + None + +--*/ +{ + + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + PCI_IO_DEVICE *RootBridgeDev; + UINT16 MinBus; + UINT16 MaxBus; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; + + MinBus = 0; + MaxBus = PCI_MAX_BUS; + Descriptors = NULL; + + // + // If this host bridge has been already enumerated, then return successfully + // + if (RootBridgeExisted (Controller)) { + return EFI_SUCCESS; + } + + // + // Open the IO Abstraction(s) needed to perform the supported test + // + Status = gBS->OpenProtocol ( + Controller , + &gEfiDevicePathProtocolGuid, + (VOID **)&ParentDevicePath, + gPciBusDriverBinding.DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { + return Status; + } + + // + // Open pci root bridge io protocol + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciRootBridgeIoProtocolGuid, + (VOID **) &PciRootBridgeIo, + gPciBusDriverBinding.DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { + return Status; + } + + // + // Load all EFI Drivers from all PCI Option ROMs behind the PCI Root Bridge + // + Status = PciRomLoadEfiDriversFromOptionRomTable (&gPciBusDriverBinding, PciRootBridgeIo); + + Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors); + + if (EFI_ERROR (Status)) { + return Status; + } + + while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) { + + // + // Create a device node for root bridge device with a NULL host bridge controller handle + // + RootBridgeDev = CreateRootBridge (Controller); + + // + // Record the root bridge device path + // + RootBridgeDev->DevicePath = ParentDevicePath; + + // + // Record the root bridge io protocol + // + RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo; + + Status = PciPciDeviceInfoCollector ( + RootBridgeDev, + (UINT8) MinBus + ); + + if (!EFI_ERROR (Status)) { + + // + // If successfully, insert the node into device pool + // + InsertRootBridge (RootBridgeDev); + } else { + + // + // If unsuccessly, destroy the entire node + // + DestroyRootBridge (RootBridgeDev); + } + + Descriptors++; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PciGetBusRange ( + IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors, + OUT UINT16 *MinBus, + OUT UINT16 *MaxBus, + OUT UINT16 *BusRange + ) +/*++ + +Routine Description: + + Get the bus range. + +Arguments: + + Descriptors - A pointer to the address space descriptor. + MinBus - The min bus. + MaxBus - The max bus. + BusRange - The bus range. + +Returns: + + Status Code. + +--*/ +{ + + while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) { + if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) { + if (MinBus != NULL) { + *MinBus = (UINT16)(*Descriptors)->AddrRangeMin; + } + + if (MaxBus != NULL) { + *MaxBus = (UINT16)(*Descriptors)->AddrRangeMax; + } + + if (BusRange != NULL) { + *BusRange = (UINT16)(*Descriptors)->AddrLen; + } + return EFI_SUCCESS; + } + + (*Descriptors)++; + } + + return EFI_NOT_FOUND; +} + diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciEnumeratorSupport.h b/CorebootModulePkg/PciBusNoEnumerationDxe/PciEnumeratorSupport.h new file mode 100644 index 0000000000..aa2aba2efe --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciEnumeratorSupport.h @@ -0,0 +1,108 @@ +/*++ + +Copyright (c) 2005 - 2006, 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: + + PciEnumeratorSupport.h + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#ifndef _EFI_PCI_ENUMERATOR_SUPPORT_H +#define _EFI_PCI_ENUMERATOR_SUPPORT_H + +#include "PciBus.h" + +EFI_STATUS +PciPciDeviceInfoCollector ( + IN PCI_IO_DEVICE *Bridge, + UINT8 StartBusNumber + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Bridge - TODO: add argument description + StartBusNumber - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciDevicePresent( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + PCI_TYPE00 *Pci, + UINT8 Bus, + UINT8 Device, + UINT8 Func +); + +EFI_STATUS +PciEnumeratorLight ( + IN EFI_HANDLE Controller + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Controller - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +PciGetBusRange ( + IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors, + OUT UINT16 *MinBus, + OUT UINT16 *MaxBus, + OUT UINT16 *BusRange + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + Descriptors - TODO: add argument description + MinBus - TODO: add argument description + MaxBus - TODO: add argument description + BusRange - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; +#endif diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciIo.c b/CorebootModulePkg/PciBusNoEnumerationDxe/PciIo.c new file mode 100644 index 0000000000..bf3c1a6ba7 --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciIo.c @@ -0,0 +1,1852 @@ +/*++ + +Copyright (c) 2005 - 2014, 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: + + PciIo.c + +Abstract: + + PCI I/O Abstraction Driver + +Revision History + +--*/ + +#include "PciBus.h" + +// +// PCI I/O Support Function Prototypes +// +// + +BOOLEAN +PciDevicesOnTheSamePath ( + IN PCI_IO_DEVICE *PciDevice1, + IN PCI_IO_DEVICE *PciDevice2 +); + + +EFI_STATUS +UpStreamBridgesAttributes ( + IN PCI_IO_DEVICE *PciIoDevice, + IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation, + IN UINT64 Attributes +); + + +BOOLEAN +CheckBarType ( + IN PCI_IO_DEVICE *PciIoDevice, + UINT8 BarIndex, + PCI_BAR_TYPE BarType +); + + +EFI_STATUS +SetBootVGA ( + IN PCI_IO_DEVICE *PciIoDevice +); + +EFI_STATUS +DisableBootVGA ( + IN PCI_IO_DEVICE *PciIoDevice +); + + +EFI_STATUS +PciIoVerifyBarAccess ( + PCI_IO_DEVICE *PciIoDevice, + UINT8 BarIndex, + PCI_BAR_TYPE Type, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINTN Count, + UINT64 *Offset +); + +EFI_STATUS +PciIoVerifyConfigAccess ( + PCI_IO_DEVICE *PciIoDevice, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINTN Count, + IN UINT64 *Offset +); + +EFI_STATUS +EFIAPI +PciIoPollMem ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result +); + +EFI_STATUS +EFIAPI +PciIoPollIo ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result +); + +EFI_STATUS +EFIAPI +PciIoMemRead ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer +); + +EFI_STATUS +EFIAPI +PciIoMemWrite ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer +); + +EFI_STATUS +EFIAPI +PciIoIoRead ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer +); + +EFI_STATUS +EFIAPI +PciIoIoWrite ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer +); + +EFI_STATUS +EFIAPI +PciIoConfigRead ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT32 Offset, + IN UINTN Count, + IN OUT VOID *Buffer +); + +EFI_STATUS +EFIAPI +PciIoConfigWrite ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT32 Offset, + IN UINTN Count, + IN OUT VOID *Buffer +); + +EFI_STATUS +EFIAPI +PciIoCopyMem ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 DestBarIndex, + IN UINT64 DestOffset, + IN UINT8 SrcBarIndex, + IN UINT64 SrcOffset, + IN UINTN Count +); + +EFI_STATUS +EFIAPI +PciIoMap ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping +); + +EFI_STATUS +EFIAPI +PciIoUnmap ( + IN EFI_PCI_IO_PROTOCOL *This, + IN VOID *Mapping +); + +EFI_STATUS +EFIAPI +PciIoAllocateBuffer ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes +); + +EFI_STATUS +EFIAPI +PciIoFreeBuffer ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINTN Pages, + IN VOID *HostAddress + ); + +EFI_STATUS +EFIAPI +PciIoFlush ( + IN EFI_PCI_IO_PROTOCOL *This + ); + +EFI_STATUS +EFIAPI +PciIoGetLocation ( + IN EFI_PCI_IO_PROTOCOL *This, + OUT UINTN *Segment, + OUT UINTN *Bus, + OUT UINTN *Device, + OUT UINTN *Function + ); + +EFI_STATUS +EFIAPI +PciIoAttributes ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation, + IN UINT64 Attributes, + OUT UINT64 *Result OPTIONAL + ); + +EFI_STATUS +EFIAPI +PciIoGetBarAttributes( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT8 BarIndex, + OUT UINT64 *Supports, OPTIONAL + OUT VOID **Resources OPTIONAL + ); + +EFI_STATUS +EFIAPI +PciIoSetBarAttributes( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN UINT8 BarIndex, + IN OUT UINT64 *Offset, + IN OUT UINT64 *Length + ); + + +// +// Pci Io Protocol Interface +// +EFI_PCI_IO_PROTOCOL PciIoInterface = { + PciIoPollMem, + PciIoPollIo, + { + PciIoMemRead, + PciIoMemWrite + }, + { + PciIoIoRead, + PciIoIoWrite + }, + { + PciIoConfigRead, + PciIoConfigWrite + }, + PciIoCopyMem, + PciIoMap, + PciIoUnmap, + PciIoAllocateBuffer, + PciIoFreeBuffer, + PciIoFlush, + PciIoGetLocation, + PciIoAttributes, + PciIoGetBarAttributes, + PciIoSetBarAttributes, + 0, + NULL +}; + + +EFI_STATUS +InitializePciIoInstance ( + PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + Initializes a PCI I/O Instance + +Arguments: + +Returns: + + None + +--*/ + +{ + CopyMem (&PciIoDevice->PciIo, &PciIoInterface, sizeof (EFI_PCI_IO_PROTOCOL)); + return EFI_SUCCESS; +} + +EFI_STATUS +PciIoVerifyBarAccess ( + PCI_IO_DEVICE *PciIoDevice, + UINT8 BarIndex, + PCI_BAR_TYPE Type, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINTN Count, + UINT64 *Offset + ) +/*++ + +Routine Description: + + Verifies access to a PCI Base Address Register (BAR) + +Arguments: + +Returns: + + None + +--*/ +{ + if ((UINT32)Width >= EfiPciIoWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + if (BarIndex == EFI_PCI_IO_PASS_THROUGH_BAR) { + return EFI_SUCCESS; + } + + // + // BarIndex 0-5 is legal + // + if (BarIndex >= PCI_MAX_BAR) { + return EFI_INVALID_PARAMETER; + } + + if (!CheckBarType (PciIoDevice, BarIndex, Type)) { + return EFI_INVALID_PARAMETER; + } + + // + // If Width is EfiPciIoWidthFifoUintX then convert to EfiPciIoWidthUintX + // If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX + // + if (Width >= EfiPciIoWidthFifoUint8 && Width <= EfiPciIoWidthFifoUint64) { + Count = 1; + } + + Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & 0x03); + + if ((*Offset + Count * ((UINTN)1 << Width)) - 1 >= PciIoDevice->PciBar[BarIndex].Length) { + return EFI_INVALID_PARAMETER; + } + + *Offset = *Offset + PciIoDevice->PciBar[BarIndex].BaseAddress; + + return EFI_SUCCESS; +} + +EFI_STATUS +PciIoVerifyConfigAccess ( + PCI_IO_DEVICE *PciIoDevice, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINTN Count, + IN UINT64 *Offset + ) +/*++ + +Routine Description: + + Verifies access to a PCI Config Header + +Arguments: + +Returns: + + None + +--*/ +{ + UINT64 ExtendOffset; + + if ((UINT32)Width >= EfiPciIoWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + // + // If Width is EfiPciIoWidthFifoUintX then convert to EfiPciIoWidthUintX + // If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX + // + Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & 0x03); + + if (PciIoDevice->IsPciExp) { + if ((*Offset + Count * ((UINTN)1 << Width)) - 1 >= PCI_EXP_MAX_CONFIG_OFFSET) { + return EFI_UNSUPPORTED; + } + + ExtendOffset = LShiftU64 (*Offset, 32); + *Offset = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber, 0); + *Offset = (*Offset) | ExtendOffset; + + } else { + if ((*Offset + Count * ((UINTN)1 << Width)) - 1 >= PCI_MAX_CONFIG_OFFSET) { + return EFI_UNSUPPORTED; + } + + *Offset = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber, *Offset); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PciIoPollMem ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ) +/*++ + +Routine Description: + + Poll PCI Memmory + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + if ((UINT32)Width >= EfiPciIoWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, 1, &Offset); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + if (Width > EfiPciIoWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + Status = PciIoDevice->PciRootBridgeIo->PollMem ( + PciIoDevice->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Offset, + Mask, + Value, + Delay, + Result + ); + return Status; +} + +EFI_STATUS +EFIAPI +PciIoPollIo ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ) +/*++ + +Routine Description: + + Poll PCI IO + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + if ((UINT32)Width > EfiPciIoWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, 1, &Offset); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status = PciIoDevice->PciRootBridgeIo->PollIo ( + PciIoDevice->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Offset, + Mask, + Value, + Delay, + Result + ); + + return Status; +} + +EFI_STATUS +EFIAPI +PciIoMemRead ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Performs a PCI Memory Read Cycle + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + if (Buffer == NULL){ + return EFI_INVALID_PARAMETER; + } + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + if ((UINT32)Width >= EfiPciIoWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, Count, &Offset); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status = PciIoDevice->PciRootBridgeIo->Mem.Read ( + PciIoDevice->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Offset, + Count, + Buffer + ); + + return Status; +} + +EFI_STATUS +EFIAPI +PciIoMemWrite ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Performs a PCI Memory Write Cycle + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + if (Buffer == NULL){ + return EFI_INVALID_PARAMETER; + } + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + if ((UINT32)Width >= EfiPciIoWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, Count, &Offset); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status = PciIoDevice->PciRootBridgeIo->Mem.Write ( + PciIoDevice->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Offset, + Count, + Buffer + ); + + return Status; +} + +EFI_STATUS +EFIAPI +PciIoIoRead ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Performs a PCI I/O Read Cycle + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + if (Buffer == NULL){ + return EFI_INVALID_PARAMETER; + } + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + if ((UINT32)Width >= EfiPciIoWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, Count, &Offset); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status = PciIoDevice->PciRootBridgeIo->Io.Read ( + PciIoDevice->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Offset, + Count, + Buffer + ); + + return Status; +} + +EFI_STATUS +EFIAPI +PciIoIoWrite ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Performs a PCI I/O Write Cycle + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + if (Buffer == NULL){ + return EFI_INVALID_PARAMETER; + } + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + if ((UINT32)Width >= EfiPciIoWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, Count, &Offset); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status = PciIoDevice->PciRootBridgeIo->Io.Write ( + PciIoDevice->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Offset, + Count, + Buffer + ); + + return Status; +} + +EFI_STATUS +EFIAPI +PciIoConfigRead ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT32 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Performs a PCI Configuration Read Cycle + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + UINT64 Address; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + Address = Offset; + Status = PciIoVerifyConfigAccess (PciIoDevice, Width, Count, &Address); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PciIoDevice->PciRootBridgeIo->Pci.Read ( + PciIoDevice->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Address, + Count, + Buffer + ); + + return Status; +} + +EFI_STATUS +EFIAPI +PciIoConfigWrite ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT32 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Performs a PCI Configuration Write Cycle + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + UINT64 Address; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + Address = Offset; + Status = PciIoVerifyConfigAccess (PciIoDevice, Width, Count, &Address); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PciIoDevice->PciRootBridgeIo->Pci.Write ( + PciIoDevice->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Address, + Count, + Buffer + ); + + return Status; +} + +EFI_STATUS +EFIAPI +PciIoCopyMem ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 DestBarIndex, + IN UINT64 DestOffset, + IN UINT8 SrcBarIndex, + IN UINT64 SrcOffset, + IN UINTN Count + ) +/*++ + +Routine Description: + + Copy PCI Memory + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + if ((UINT32)Width >= EfiPciIoWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + if (Width == EfiPciIoWidthFifoUint8 || + Width == EfiPciIoWidthFifoUint16 || + Width == EfiPciIoWidthFifoUint32 || + Width == EfiPciIoWidthFifoUint64 || + Width == EfiPciIoWidthFillUint8 || + Width == EfiPciIoWidthFillUint16 || + Width == EfiPciIoWidthFillUint32 || + Width == EfiPciIoWidthFillUint64) { + return EFI_INVALID_PARAMETER; + } + + Status = PciIoVerifyBarAccess (PciIoDevice, DestBarIndex, PciBarTypeMem, Width, Count, &DestOffset); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status = PciIoVerifyBarAccess (PciIoDevice, SrcBarIndex, PciBarTypeMem, Width, Count, &SrcOffset); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + Status = PciIoDevice->PciRootBridgeIo->CopyMem ( + PciIoDevice->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + DestOffset, + SrcOffset, + Count + ); + + return Status; +} + +EFI_STATUS +EFIAPI +PciIoMap ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +/*++ + +Routine Description: + + Maps a memory region for DMA + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + if ((UINT32)Operation >= EfiPciIoOperationMaximum) { + return EFI_INVALID_PARAMETER; + } + + if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) { + Operation = (EFI_PCI_IO_PROTOCOL_OPERATION) (Operation + EfiPciOperationBusMasterRead64); + } + + Status = PciIoDevice->PciRootBridgeIo->Map ( + PciIoDevice->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) Operation, + HostAddress, + NumberOfBytes, + DeviceAddress, + Mapping + ); + + return Status; +} + +EFI_STATUS +EFIAPI +PciIoUnmap ( + IN EFI_PCI_IO_PROTOCOL *This, + IN VOID *Mapping + ) +/*++ + +Routine Description: + + Unmaps a memory region for DMA + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + Status = PciIoDevice->PciRootBridgeIo->Unmap ( + PciIoDevice->PciRootBridgeIo, + Mapping + ); + + return Status; +} + +EFI_STATUS +EFIAPI +PciIoAllocateBuffer ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ) +/*++ + +Routine Description: + + Allocates a common buffer for DMA + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + if (Attributes & + (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED))) { + return EFI_UNSUPPORTED; + } + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + if (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) { + Attributes |= EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE; + } + + Status = PciIoDevice->PciRootBridgeIo->AllocateBuffer ( + PciIoDevice->PciRootBridgeIo, + Type, + MemoryType, + Pages, + HostAddress, + Attributes + ); + + return Status; +} + +EFI_STATUS +EFIAPI +PciIoFreeBuffer ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINTN Pages, + IN VOID *HostAddress + ) +/*++ + +Routine Description: + + Frees a common buffer + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + + if( HostAddress == NULL ){ + return EFI_INVALID_PARAMETER; + } + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + Status = PciIoDevice->PciRootBridgeIo->FreeBuffer ( + PciIoDevice->PciRootBridgeIo, + Pages, + HostAddress + ); + + return Status; +} + +EFI_STATUS +EFIAPI +PciIoFlush ( + IN EFI_PCI_IO_PROTOCOL *This + ) +/*++ + +Routine Description: + + Flushes a DMA buffer + +Arguments: + +Returns: + + None + +--*/ + +{ + EFI_STATUS Status; + UINT32 Register; + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + // + // If the device is behind a PCI-PCI Bridge, then perform a read cycles to the device to + // flush the posted write cycles through the PCI-PCI bridges + // + if (PciIoDevice->Parent != NULL) { + Status = This->Pci.Read (This, EfiPciIoWidthUint32, 0, 1, &Register); + } + + // + // Call the PCI Root Bridge I/O Protocol to flush the posted write cycles through the chipset + // + Status = PciIoDevice->PciRootBridgeIo->Flush ( + PciIoDevice->PciRootBridgeIo + ); + + return Status; +} + +EFI_STATUS +EFIAPI +PciIoGetLocation ( + IN EFI_PCI_IO_PROTOCOL *This, + OUT UINTN *Segment, + OUT UINTN *Bus, + OUT UINTN *Device, + OUT UINTN *Function + ) +/*++ + +Routine Description: + + Gets a PCI device's current bus number, device number, and function number. + +Arguments: + +Returns: + + None + +--*/ +{ + PCI_IO_DEVICE *PciIoDevice; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + if (Segment == NULL || Bus == NULL || Device == NULL || Function == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Segment = PciIoDevice->PciRootBridgeIo->SegmentNumber; + *Bus = PciIoDevice->BusNumber; + *Device = PciIoDevice->DeviceNumber; + *Function = PciIoDevice->FunctionNumber; + + return EFI_SUCCESS; +} + +BOOLEAN +CheckBarType ( + IN PCI_IO_DEVICE *PciIoDevice, + UINT8 BarIndex, + PCI_BAR_TYPE BarType + ) +/*++ + +Routine Description: + + Sets a PCI controllers attributes on a resource range + +Arguments: + +Returns: + + None + +--*/ +{ + switch (BarType) { + + case PciBarTypeMem: + + if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeMem32 && + PciIoDevice->PciBar[BarIndex].BarType != PciBarTypePMem32 && + PciIoDevice->PciBar[BarIndex].BarType != PciBarTypePMem64 && + PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeMem64 ) { + return FALSE; + } + + return TRUE; + + case PciBarTypeIo: + if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeIo32 && + PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeIo16){ + return FALSE; + } + + return TRUE; + + default: + break; + } + + return FALSE; +} + +EFI_STATUS +EFIAPI +PciIoAttributes ( + IN EFI_PCI_IO_PROTOCOL * This, + IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation, + IN UINT64 Attributes, + OUT UINT64 *Result OPTIONAL + ) +/*++ + +Routine Description: + + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + + PCI_IO_DEVICE *PciIoDevice; + PCI_IO_DEVICE *Temp; + UINT64 NewAttributes; + UINT64 PciRootBridgeSupports; + UINT64 PciRootBridgeAttributes; + UINT64 NewPciRootBridgeAttributes; + UINT64 NewUpStreamBridgeAttributes; + UINT64 ModifiedPciRootBridgeAttributes; + UINT16 EnableCommand; + UINT16 DisableCommand; + UINT16 EnableBridge; + UINT16 DisableBridge; + UINT16 Command; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + NewUpStreamBridgeAttributes = 0; + + EnableCommand = 0; + DisableCommand = 0; + EnableBridge = 0; + DisableBridge = 0; + + switch (Operation) { + case EfiPciIoAttributeOperationGet: + if (Result == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Result = PciIoDevice->Attributes; + return EFI_SUCCESS; + + case EfiPciIoAttributeOperationSupported: + if (Result == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Result = PciIoDevice->Supports; + return EFI_SUCCESS; + + case EfiPciIoAttributeOperationEnable: + if(Attributes & ~(PciIoDevice->Supports)) { + return EFI_UNSUPPORTED; + } + NewAttributes = PciIoDevice->Attributes | Attributes; + break; + case EfiPciIoAttributeOperationDisable: + if(Attributes & ~(PciIoDevice->Supports)) { + return EFI_UNSUPPORTED; + } + NewAttributes = PciIoDevice->Attributes & (~Attributes); + break; + case EfiPciIoAttributeOperationSet: + if(Attributes & ~(PciIoDevice->Supports)) { + return EFI_UNSUPPORTED; + } + NewAttributes = Attributes; + break; + default: + return EFI_INVALID_PARAMETER; + } + + // + // If VGA_IO is set, then set VGA_MEMORY too. This driver can not enable them seperately. + // + if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO) { + NewAttributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY; + } + + // + // If VGA_MEMORY is set, then set VGA_IO too. This driver can not enable them seperately. + // + if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY) { + NewAttributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO; + } + + // + // If the attributes are already set correctly, then just return EFI_SUCCESS; + // + if ((NewAttributes ^ PciIoDevice->Attributes) == 0) { + return EFI_SUCCESS; + } + + // + // This driver takes care of EFI_PCI_IO_ATTRIBUTE_IO, EFI_PCI_IO_ATTRIBUTE_MEMORY, and + // EFI_PCI_IO_ATTRIBUTE_BUS_MASTER. Strip these 3 bits off the new attribute mask so + // a call to the PCI Root Bridge I/O Protocol can be made + // + + if (!IS_PCI_BRIDGE(&PciIoDevice->Pci)) { + NewPciRootBridgeAttributes = NewAttributes & (~(EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER | EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE)); + + // + // Get the current attributes of this PCI device's PCI Root Bridge + // + Status = PciIoDevice->PciRootBridgeIo->GetAttributes ( + PciIoDevice->PciRootBridgeIo, + &PciRootBridgeSupports, + &PciRootBridgeAttributes + ); + + // + // Check to see if any of the PCI Root Bridge attributes are being modified + // + ModifiedPciRootBridgeAttributes = NewPciRootBridgeAttributes ^ PciRootBridgeAttributes; + if (ModifiedPciRootBridgeAttributes) { + + // + // Check to see if the PCI Root Bridge supports modifiying the attributes that are changing + // + if ((ModifiedPciRootBridgeAttributes & PciRootBridgeSupports) != ModifiedPciRootBridgeAttributes) { + // return EFI_UNSUPPORTED; + } + // + // Call the PCI Root Bridge to attempt to modify the attributes + // + Status = PciIoDevice->PciRootBridgeIo->SetAttributes ( + PciIoDevice->PciRootBridgeIo, + NewPciRootBridgeAttributes, + NULL, + NULL + ); + if (EFI_ERROR (Status)) { + // + // The PCI Root Bridge could not modify the attributes, so return the error. + // + return Status; + } + } + } + + + if (IS_PCI_BRIDGE(&PciIoDevice->Pci)) { + + + // + // Check to see if an VGA related attributes are being set. + // + if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO)) { + + if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO) { + EnableBridge |= EFI_PCI_BRIDGE_CONTROL_VGA; + } else { + DisableBridge |= EFI_PCI_BRIDGE_CONTROL_VGA; + } + } + + // + // Check to see if an VGA related attributes are being set. + // If ISA Enable on the PPB is set, the PPB will block the + // 0x100-0x3FF for each 1KB block in the first 64K I/O block + // + if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_ISA_IO) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_ISA_IO)) { + + if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_ISA_IO) { + DisableBridge |= EFI_PCI_BRIDGE_CONTROL_ISA; + } else { + EnableBridge |= EFI_PCI_BRIDGE_CONTROL_ISA; + } + } + + // + // Check to see if an VGA related attributes are being set. + // + if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO)) { + + if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO) { + EnableCommand |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP; + } else { + DisableCommand |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP; + } + } + + } else { + + if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO)) { + + if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO) { + + // + //Check if there have been an active VGA device on the same segment + // + Temp = ActiveVGADeviceOnTheSameSegment (PciIoDevice); + + if (Temp && Temp != PciIoDevice) { + return EFI_UNSUPPORTED; + } + } + } + + if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO)) { + if (IS_PCI_GFX(&PciIoDevice->Pci)) { + + // + //Get the boot VGA on the same segement + // + Temp = ActiveVGADeviceOnTheSameSegment (PciIoDevice); + + if (!Temp) { + + // + // If there is no VGA device on the segement, set + // this graphics card to decode the palette range + // + DisableCommand |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP; + } else { + + // + // Check these two agents are on the same path + // + if (PciDevicesOnTheSamePath(Temp, PciIoDevice)) { + + // + // Check if they are on the same bus + // + if (Temp->Parent == PciIoDevice->Parent) { + + PciReadCommandRegister (Temp, &Command); + + // + // If they are on the same bus, either one can + // be set to snoop, the other set to decode + // + if (Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) { + DisableCommand |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP; + } else { + EnableCommand |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP; + } + } else { + + // + // If they are on the same path but on the different bus + // The first agent is set to snoop, the second one set to + // decode + // + if (Temp->BusNumber > PciIoDevice->BusNumber) { + PciEnableCommandRegister(Temp,EFI_PCI_COMMAND_VGA_PALETTE_SNOOP); + DisableCommand |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP; + } else { + PciDisableCommandRegister(Temp,EFI_PCI_COMMAND_VGA_PALETTE_SNOOP); + EnableCommand |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP; + } + } + } else { + + EnableCommand |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP; + } + } + } + } + } + + // + // Check to see of the I/O enable is being modified + // + if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_IO) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_IO)) { + if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_IO) { + EnableCommand |= EFI_PCI_COMMAND_IO_SPACE; + } else { + DisableCommand |= EFI_PCI_COMMAND_IO_SPACE; + } + } + + // + // Check to see of the Memory enable is being modified + // + if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_MEMORY) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_MEMORY)) { + if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_MEMORY) { + EnableCommand |= EFI_PCI_COMMAND_MEMORY_SPACE; + } else { + DisableCommand |= EFI_PCI_COMMAND_MEMORY_SPACE; + } + } + + // + // Check to see of the Bus Master enable is being modified + // + if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_BUS_MASTER)) { + if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) { + EnableCommand |= EFI_PCI_COMMAND_BUS_MASTER; + } else { + DisableCommand |= EFI_PCI_COMMAND_BUS_MASTER; + } + } + + Status = EFI_SUCCESS; + if (EnableCommand) { + Status = PciEnableCommandRegister(PciIoDevice, EnableCommand); + } + + if (DisableCommand) { + Status = PciDisableCommandRegister(PciIoDevice, DisableCommand); + } + + if (EFI_ERROR(Status)) { + return EFI_UNSUPPORTED; + } + + if (EnableBridge) { + Status = PciEnableBridgeControlRegister(PciIoDevice, EnableBridge); + } + + if (DisableBridge) { + Status = PciDisableBridgeControlRegister(PciIoDevice, DisableBridge); + } + + if (EFI_ERROR(Status)) { + return EFI_UNSUPPORTED; + } + + // + // Set the upstream bridge attributes + // + if (Operation != EfiPciIoAttributeOperationGet && Operation != EfiPciIoAttributeOperationSupported) { + + // + // EFI_PCI_IO_ATTRIBUTE_MEMORY, EFI_PCI_IO_ATTRIBUTE_IO, EFI_PCI_IO_ATTRIBUTE_BUS_MASTER + // EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE, EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED + // EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE will not effect to upstream bridge + // + NewUpStreamBridgeAttributes = Attributes & \ + (~(EFI_PCI_IO_ATTRIBUTE_IO | \ + EFI_PCI_IO_ATTRIBUTE_MEMORY | \ + EFI_PCI_IO_ATTRIBUTE_BUS_MASTER | \ + EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE | \ + EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED | \ + EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE)); + + if (NewUpStreamBridgeAttributes){ + UpStreamBridgesAttributes(PciIoDevice, Operation, NewUpStreamBridgeAttributes); + } + } + + PciIoDevice->Attributes = NewAttributes; + + return Status; +} + +EFI_STATUS +EFIAPI +PciIoGetBarAttributes ( + IN EFI_PCI_IO_PROTOCOL * This, + IN UINT8 BarIndex, + OUT UINT64 *Supports, OPTIONAL + OUT VOID **Resources OPTIONAL + ) +/*++ + +Routine Description: + + +Arguments: + +Returns: + + None + +--*/ +{ + UINT8 *Configuration; + PCI_IO_DEVICE *PciIoDevice; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AddressSpace; + EFI_ACPI_END_TAG_DESCRIPTOR *End; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + if (Supports == NULL && Resources == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((BarIndex >= PCI_MAX_BAR) || (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeUnknown)) { + return EFI_UNSUPPORTED; + } + + // + // This driver does not support modifications to the WRITE_COMBINE or + // CACHED attributes for BAR ranges. + // + if (Supports != NULL) { + *Supports = PciIoDevice->Supports & EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED & EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE; + } + + if (Resources != NULL) { + Configuration = AllocateZeroPool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)); + if (Configuration == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + AddressSpace = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; + + AddressSpace->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + AddressSpace->Len = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3); + + AddressSpace->AddrRangeMin = PciIoDevice->PciBar[BarIndex].BaseAddress; + AddressSpace->AddrLen = PciIoDevice->PciBar[BarIndex].Length; + AddressSpace->AddrRangeMax = PciIoDevice->PciBar[BarIndex].Alignment; + + switch (PciIoDevice->PciBar[BarIndex].BarType) { + case PciBarTypeIo16: + case PciBarTypeIo32: + // + // Io + // + AddressSpace->ResType = ACPI_ADDRESS_SPACE_TYPE_IO; + break; + + case PciBarTypeMem32: + // + // Mem + // + AddressSpace->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + // + // 32 bit + // + AddressSpace->AddrSpaceGranularity = 32; + break; + + case PciBarTypePMem32: + // + // Mem + // + AddressSpace->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + // + // prefechable + // + AddressSpace->SpecificFlag = 0x6; + // + // 32 bit + // + AddressSpace->AddrSpaceGranularity = 32; + break; + + case PciBarTypeMem64: + // + // Mem + // + AddressSpace->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + // + // 64 bit + // + AddressSpace->AddrSpaceGranularity = 64; + break; + + case PciBarTypePMem64: + // + // Mem + // + AddressSpace->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; + // + // prefechable + // + AddressSpace->SpecificFlag = 0x6; + // + // 64 bit + // + AddressSpace->AddrSpaceGranularity = 64; + break; + + default: + break; + } + + // + // put the checksum + // + End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (AddressSpace + 1); + End->Desc = ACPI_END_TAG_DESCRIPTOR; + End->Checksum = 0; + + *Resources = Configuration; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PciIoSetBarAttributes ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN UINT8 BarIndex, + IN OUT UINT64 *Offset, + IN OUT UINT64 *Length + ) +/*++ + +Routine Description: + + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + PCI_IO_DEVICE *PciIoDevice; + UINT64 NonRelativeOffset; + UINT64 Supports; + + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This); + + // + // Make sure Offset and Length are not NULL + // + if (Offset == NULL || Length == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeUnknown) { + return EFI_UNSUPPORTED; + } + // + // This driver does not support setting the WRITE_COMBINE or the CACHED attributes. + // If Attributes is not 0, then return EFI_UNSUPPORTED. + // + Supports = PciIoDevice->Supports & EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED & EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE; + + if (Attributes != (Attributes & Supports)) { + return EFI_UNSUPPORTED; + } + // + // Attributes must be supported. Make sure the BAR range describd by BarIndex, Offset, and + // Length are valid for this PCI device. + // + NonRelativeOffset = *Offset; + Status = PciIoVerifyBarAccess ( + PciIoDevice, + BarIndex, + PciBarTypeMem, + EfiPciIoWidthUint8, + (UINT32) *Length, + &NonRelativeOffset + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +UpStreamBridgesAttributes ( + IN PCI_IO_DEVICE *PciIoDevice, + IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation, + IN UINT64 Attributes + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + PCI_IO_DEVICE *Parent; + EFI_PCI_IO_PROTOCOL *PciIo; + + Parent = PciIoDevice->Parent; + + while (Parent && IS_PCI_BRIDGE (&Parent->Pci)) { + + // + // Get the PciIo Protocol + // + PciIo = &Parent->PciIo; + + PciIo->Attributes (PciIo, Operation, Attributes, NULL); + + Parent = Parent->Parent; + } + + return EFI_SUCCESS; +} + +BOOLEAN +PciDevicesOnTheSamePath ( + IN PCI_IO_DEVICE *PciDevice1, + IN PCI_IO_DEVICE *PciDevice2 + ) +/*++ + +Routine Description: + +Arguments: + + PciDevice1 - The pointer to the first PCI_IO_DEVICE. + PciDevice2 - The pointer to the second PCI_IO_DEVICE. + +Returns: + + TRUE - The two Pci devices are on the same path. + FALSE - The two Pci devices are not on the same path. + +--*/ +{ + + if (PciDevice1->Parent == PciDevice2->Parent) { + return TRUE; + } + + return (BOOLEAN) ((PciDeviceExisted (PciDevice1->Parent, PciDevice2)|| PciDeviceExisted (PciDevice2->Parent, PciDevice1))); +} diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciIo.h b/CorebootModulePkg/PciBusNoEnumerationDxe/PciIo.h new file mode 100644 index 0000000000..b0d465a55a --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciIo.h @@ -0,0 +1,48 @@ +/*++ + +Copyright (c) 2005 - 2006, 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: + + PciIo.h + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#ifndef _EFI_PCI_IO_PROTOCOL_H +#define _EFI_PCI_IO_PROTOCOL_H + +EFI_STATUS +InitializePciIoInstance ( + PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciOptionRomSupport.c b/CorebootModulePkg/PciBusNoEnumerationDxe/PciOptionRomSupport.c new file mode 100644 index 0000000000..df0ae4e256 --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciOptionRomSupport.c @@ -0,0 +1,557 @@ +/*++ + +Copyright (c) 2005 - 2012, 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: + + PciOptionRomSupport.c + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#include "PciBus.h" + + +EFI_STATUS +RomDecode ( + IN PCI_IO_DEVICE *PciDevice, + IN UINT8 RomBarIndex, + IN UINT32 RomBar, + IN BOOLEAN Enable +); + +EFI_STATUS +GetOpRomInfo ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + UINT8 RomBarIndex; + UINT32 AllOnes; + UINT64 Address; + EFI_STATUS Status; + UINT8 Bus; + UINT8 Device; + UINT8 Function; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + + Bus = PciIoDevice->BusNumber; + Device = PciIoDevice->DeviceNumber; + Function = PciIoDevice->FunctionNumber; + + PciRootBridgeIo = PciIoDevice->PciRootBridgeIo; + + // + // offset is 0x30 if is not ppb + // + + // + // 0x30 + // + RomBarIndex = PCI_EXPANSION_ROM_BASE; + + if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) { + // + // if is ppb + // + + // + // 0x38 + // + RomBarIndex = PCI_BRIDGE_ROMBAR; + } + // + // the bit0 is 0 to prevent the enabling of the Rom address decoder + // + AllOnes = 0xfffffffe; + Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex); + + Status = PciRootBridgeIo->Pci.Write ( + PciRootBridgeIo, + EfiPciWidthUint32, + Address, + 1, + &AllOnes + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // read back + // + Status = PciRootBridgeIo->Pci.Read ( + PciRootBridgeIo, + EfiPciWidthUint32, + Address, + 1, + &AllOnes + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Bits [1, 10] are reserved + // + AllOnes &= 0xFFFFF800; + if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) { + return EFI_NOT_FOUND; + } + + DEBUG ((EFI_D_ERROR, "PCIBUS: GetOpRomInfo: OPROM detected!\n")); + DEBUG ((EFI_D_ERROR, "PCIBUS: GetOpRomInfo: B-%x, D-%x, F-%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Function)); + + PciIoDevice->RomSize = (UINT64) ((~AllOnes) + 1); + return EFI_SUCCESS; +} + +EFI_STATUS +LoadOpRomImage ( + IN PCI_IO_DEVICE *PciDevice, + IN UINT64 ReservedMemoryBase + ) +/*++ + +Routine Description: + + Load option rom image for specified PCI device + +Arguments: + +Returns: + +--*/ +{ + UINT8 RomBarIndex; + UINT8 Indicator; + UINT16 OffsetPcir; + UINT32 RomBarOffset; + UINT32 RomBar; + EFI_STATUS retStatus; + BOOLEAN FirstCheck; + UINT8 *Image; + PCI_EXPANSION_ROM_HEADER *RomHeader; + PCI_DATA_STRUCTURE *RomPcir; + UINT64 RomSize; + UINT64 RomImageSize; + UINT32 LegacyImageLength; + UINT8 *RomInMemory; + UINT8 CodeType; + + RomSize = PciDevice->RomSize; + + Indicator = 0; + RomImageSize = 0; + RomInMemory = NULL; + CodeType = 0xFF; + + // + // Get the RomBarIndex + // + + // + // 0x30 + // + RomBarIndex = PCI_EXPANSION_ROM_BASE; + if (IS_PCI_BRIDGE (&(PciDevice->Pci))) { + // + // if is ppb + // + + // + // 0x38 + // + RomBarIndex = PCI_BRIDGE_ROMBAR; + } + // + // Allocate memory for Rom header and PCIR + // + RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER)); + if (RomHeader == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE)); + if (RomPcir == NULL) { + gBS->FreePool (RomHeader); + return EFI_OUT_OF_RESOURCES; + } + + RomBar = (UINT32)ReservedMemoryBase; + + // + // Enable RomBar + // + RomDecode (PciDevice, RomBarIndex, RomBar, TRUE); + + RomBarOffset = RomBar; + retStatus = EFI_NOT_FOUND; + FirstCheck = TRUE; + LegacyImageLength = 0; + + do { + PciDevice->PciRootBridgeIo->Mem.Read ( + PciDevice->PciRootBridgeIo, + EfiPciWidthUint8, + RomBarOffset, + sizeof (PCI_EXPANSION_ROM_HEADER), + (UINT8 *) RomHeader + ); + + if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) { + RomBarOffset = RomBarOffset + 512; + if (FirstCheck) { + break; + } else { + RomImageSize = RomImageSize + 512; + continue; + } + } + + FirstCheck = FALSE; + OffsetPcir = RomHeader->PcirOffset; + // + // If the pointer to the PCI Data Structure is invalid, no further images can be located. + // The PCI Data Structure must be DWORD aligned. + // + if (OffsetPcir == 0 || + (OffsetPcir & 3) != 0 || + RomImageSize + OffsetPcir + sizeof (PCI_DATA_STRUCTURE) > RomSize) { + break; + } + PciDevice->PciRootBridgeIo->Mem.Read ( + PciDevice->PciRootBridgeIo, + EfiPciWidthUint8, + RomBarOffset + OffsetPcir, + sizeof (PCI_DATA_STRUCTURE), + (UINT8 *) RomPcir + ); + // + // If a valid signature is not present in the PCI Data Structure, no further images can be located. + // + if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) { + break; + } + if (RomImageSize + RomPcir->ImageLength * 512 > RomSize) { + break; + } + if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) { + CodeType = PCI_CODE_TYPE_PCAT_IMAGE; + LegacyImageLength = ((UINT32)((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512) * 512; + } + Indicator = RomPcir->Indicator; + RomImageSize = RomImageSize + RomPcir->ImageLength * 512; + RomBarOffset = RomBarOffset + RomPcir->ImageLength * 512; + } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize)); + + // + // Some Legacy Cards do not report the correct ImageLength so used the maximum + // of the legacy length and the PCIR Image Length + // + if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) { + RomImageSize = MAX (RomImageSize, LegacyImageLength); + } + + if (RomImageSize > 0) { + retStatus = EFI_SUCCESS; + Image = AllocatePool ((UINT32) RomImageSize); + if (Image == NULL) { + RomDecode (PciDevice, RomBarIndex, RomBar, FALSE); + gBS->FreePool (RomHeader); + gBS->FreePool (RomPcir); + return EFI_OUT_OF_RESOURCES; + } + + // + // Copy Rom image into memory + // + PciDevice->PciRootBridgeIo->Mem.Read ( + PciDevice->PciRootBridgeIo, + EfiPciWidthUint8, + RomBar, + (UINT32) RomImageSize, + Image + ); + RomInMemory = Image; + } + + RomDecode (PciDevice, RomBarIndex, RomBar, FALSE); + + PciDevice->PciIo.RomSize = RomImageSize; + PciDevice->PciIo.RomImage = RomInMemory; + + // + // Free allocated memory + // + gBS->FreePool (RomHeader); + gBS->FreePool (RomPcir); + + return retStatus; +} + +EFI_STATUS +RomDecode ( + IN PCI_IO_DEVICE *PciDevice, + IN UINT8 RomBarIndex, + IN UINT32 RomBar, + IN BOOLEAN Enable + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + UINT16 CommandValue; + UINT32 Value32; + UINT64 Address; + //EFI_STATUS Status; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + + PciRootBridgeIo = PciDevice->PciRootBridgeIo; + if (Enable) { + Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, RomBarIndex); + // + // set the Rom base address: now is hardcode + // + PciRootBridgeIo->Pci.Write( + PciRootBridgeIo, + EfiPciWidthUint32, + Address, + 1, + &RomBar); + + // + // enable its decoder + // + Value32 = RomBar | 0x1; + PciRootBridgeIo->Pci.Write( + PciRootBridgeIo, + EfiPciWidthUint32, + Address, + 1, + &Value32); + + // + //setting the memory space bit in the function's command register + // + Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, 0x04); + PciRootBridgeIo->Pci.Read( + PciRootBridgeIo, + EfiPciWidthUint16, + Address, + 1, + &CommandValue); + + CommandValue = (UINT16)(CommandValue | 0x0002); //0x0003 + PciRootBridgeIo->Pci.Write( + PciRootBridgeIo, + EfiPciWidthUint16, + Address, + 1, + &CommandValue); + } else { + // + // disable rom decode + // + Address = EFI_PCI_ADDRESS (PciDevice->BusNumber, PciDevice->DeviceNumber, PciDevice->FunctionNumber, RomBarIndex); + Value32 = 0xfffffffe; + PciRootBridgeIo->Pci.Write( + PciRootBridgeIo, + EfiPciWidthUint32, + Address, + 1, + &Value32); + } + + return EFI_SUCCESS; + +} + +EFI_STATUS +ProcessOpRomImage ( + PCI_IO_DEVICE *PciDevice + ) +/*++ + +Routine Description: + + Process the oprom image. + +Arguments: + PciDevice A pointer to a pci device. + +Returns: + + EFI Status. + +--*/ +{ + UINT8 Indicator; + UINT32 ImageSize; + UINT16 ImageOffset; + VOID *RomBar; + UINT8 *RomBarOffset; + EFI_HANDLE ImageHandle; + EFI_STATUS Status; + EFI_STATUS retStatus; + BOOLEAN SkipImage; + UINT32 DestinationSize; + UINT32 ScratchSize; + UINT8 *Scratch; + VOID *ImageBuffer; + VOID *DecompressedImageBuffer; + UINT32 ImageLength; + EFI_DECOMPRESS_PROTOCOL *Decompress; + EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader; + PCI_DATA_STRUCTURE *Pcir; + UINT32 InitializationSize; + + Indicator = 0; + + // + // Get the Address of the Rom image + // + RomBar = PciDevice->PciIo.RomImage; + RomBarOffset = (UINT8 *) RomBar; + retStatus = EFI_NOT_FOUND; + + if (RomBarOffset == NULL) { + return retStatus; + } + ASSERT (((EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset)->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE); + + do { + EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset; + if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) { + RomBarOffset = RomBarOffset + 512; + continue; + } + + Pcir = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader->PcirOffset); + ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE); + ImageSize = (UINT32) (Pcir->ImageLength * 512); + Indicator = Pcir->Indicator; + + if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) && + (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) && + ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) || + (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER))) { + + ImageOffset = EfiRomHeader->EfiImageHeaderOffset; + InitializationSize = EfiRomHeader->InitializationSize * 512; + + if (InitializationSize <= ImageSize && ImageOffset < InitializationSize) { + + ImageBuffer = (VOID *) (RomBarOffset + ImageOffset); + ImageLength = InitializationSize - (UINT32)ImageOffset; + DecompressedImageBuffer = NULL; + + // + // decompress here if needed + // + SkipImage = FALSE; + if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) { + SkipImage = TRUE; + } + + if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) { + Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress); + if (EFI_ERROR (Status)) { + SkipImage = TRUE; + } else { + SkipImage = TRUE; + Status = Decompress->GetInfo ( + Decompress, + ImageBuffer, + ImageLength, + &DestinationSize, + &ScratchSize + ); + if (!EFI_ERROR (Status)) { + DecompressedImageBuffer = NULL; + DecompressedImageBuffer = AllocatePool (DestinationSize); + if (DecompressedImageBuffer != NULL) { + Scratch = AllocatePool (ScratchSize); + if (Scratch != NULL) { + Status = Decompress->Decompress ( + Decompress, + ImageBuffer, + ImageLength, + DecompressedImageBuffer, + DestinationSize, + Scratch, + ScratchSize + ); + if (!EFI_ERROR (Status)) { + ImageBuffer = DecompressedImageBuffer; + ImageLength = DestinationSize; + SkipImage = FALSE; + } + + gBS->FreePool (Scratch); + } + } + } + } + } + + if (!SkipImage) { + // + // load image and start image + // + Status = gBS->LoadImage ( + FALSE, + gPciBusDriverBinding.DriverBindingHandle, + NULL, + ImageBuffer, + ImageLength, + &ImageHandle + ); + if (!EFI_ERROR (Status)) { + Status = gBS->StartImage (ImageHandle, NULL, NULL); + if (!EFI_ERROR (Status)) { + AddDriver (PciDevice, ImageHandle); + retStatus = EFI_SUCCESS; + } + } + } + + RomBarOffset = RomBarOffset + ImageSize; + } else { + RomBarOffset = RomBarOffset + ImageSize; + } + } else { + RomBarOffset = RomBarOffset + ImageSize; + } + + } while (((Indicator & 0x80) == 0x00) && ((UINTN) (RomBarOffset - (UINT8 *) RomBar) < PciDevice->RomSize)); + + return retStatus; + +} diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciOptionRomSupport.h b/CorebootModulePkg/PciBusNoEnumerationDxe/PciOptionRomSupport.h new file mode 100644 index 0000000000..60c4989cf4 --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciOptionRomSupport.h @@ -0,0 +1,92 @@ +/*++ + +Copyright (c) 2005 - 2006, 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: + + PciOptionRomSupport.h + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#ifndef _EFI_PCI_OP_ROM_SUPPORT_H +#define _EFI_PCI_OP_ROM_SUPPORT_H + +EFI_STATUS +GetOpRomInfo ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +LoadOpRomImage ( + IN PCI_IO_DEVICE *PciDevice, + IN UINT64 ReservedMemoryBase + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciDevice - TODO: add argument description + RomBase - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +EFI_STATUS +ProcessOpRomImage ( + PCI_IO_DEVICE *PciDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciPowerManagement.c b/CorebootModulePkg/PciBusNoEnumerationDxe/PciPowerManagement.c new file mode 100644 index 0000000000..0e239cec3c --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciPowerManagement.c @@ -0,0 +1,100 @@ +/*++ + +Copyright (c) 2005 - 2012, 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: + + PciPowerManagement.c + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#include "PciBus.h" + +EFI_STATUS +EFIAPI +ResetPowerManagementFeature ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + This function is intended to turn off PWE assertion and + put the device to D0 state if the device supports + PCI Power Management. + +Arguments: + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + UINT8 PowerManagementRegBlock; + UINT16 PowerManagementCSR; + + PowerManagementRegBlock = 0; + + Status = LocateCapabilityRegBlock ( + PciIoDevice, + EFI_PCI_CAPABILITY_ID_PMI, + &PowerManagementRegBlock, + NULL + ); + + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + // + // Turn off the PWE assertion and put the device into D0 State + // + + // + // Read PMCSR + // + Status = PciIoDevice->PciIo.Pci.Read ( + &PciIoDevice->PciIo, + EfiPciIoWidthUint16, + PowerManagementRegBlock + 4, + 1, + &PowerManagementCSR + ); + if (!EFI_ERROR (Status)) { + // + // Clear PME_Status bit + // + PowerManagementCSR |= BIT15; + // + // Clear PME_En bit. PowerState = D0. + // + PowerManagementCSR &= ~(BIT8 | BIT1 | BIT0); + + // + // Write PMCSR + // + Status = PciIoDevice->PciIo.Pci.Write ( + &PciIoDevice->PciIo, + EfiPciIoWidthUint16, + PowerManagementRegBlock + 4, + 1, + &PowerManagementCSR + ); + } + return Status; +} diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciPowerManagement.h b/CorebootModulePkg/PciBusNoEnumerationDxe/PciPowerManagement.h new file mode 100644 index 0000000000..98738b394b --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciPowerManagement.h @@ -0,0 +1,49 @@ +/*++ + +Copyright (c) 2005 - 2006, 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: + + PciPowerManagement.h + +Abstract: + + PCI Bus Driver + +Revision History + +--*/ + +#ifndef _EFI_PCI_POWER_MANAGEMENT_H +#define _EFI_PCI_POWER_MANAGEMENT_H + +EFI_STATUS +EFIAPI +ResetPowerManagementFeature ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; + +#endif diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciRomTable.c b/CorebootModulePkg/PciBusNoEnumerationDxe/PciRomTable.c new file mode 100644 index 0000000000..5123b0f88c --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciRomTable.c @@ -0,0 +1,393 @@ +/*++ + +Copyright (c) 2005 - 2012, 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: + + PciRomTable.c + +Abstract: + + Option Rom Support for PCI Bus Driver + +Revision History + +--*/ + +#include "PciBus.h" + +typedef struct { + EFI_HANDLE ImageHandle; + UINTN Seg; + UINT8 Bus; + UINT8 Dev; + UINT8 Func; +} EFI_PCI_ROM_IMAGE_MAPPING; + +UINTN mNumberOfPciRomImages = 0; +UINTN mMaxNumberOfPciRomImages = 0; +EFI_PCI_ROM_IMAGE_MAPPING *mRomImageTable = NULL; + +CHAR16 mHexDigit[17] = L"0123456789ABCDEF"; + +VOID +PciRomAddImageMapping ( + IN EFI_HANDLE ImageHandle, + IN UINTN Seg, + IN UINT8 Bus, + IN UINT8 Dev, + IN UINT8 Func + ) + +{ + EFI_PCI_ROM_IMAGE_MAPPING *TempMapping; + + if (mNumberOfPciRomImages >= mMaxNumberOfPciRomImages) { + + mMaxNumberOfPciRomImages += 0x20; + + TempMapping = NULL; + TempMapping = AllocatePool (mMaxNumberOfPciRomImages * sizeof (EFI_PCI_ROM_IMAGE_MAPPING)); + if (TempMapping == NULL) { + return ; + } + + CopyMem (TempMapping, mRomImageTable, mNumberOfPciRomImages * sizeof (EFI_PCI_ROM_IMAGE_MAPPING)); + + if (mRomImageTable != NULL) { + gBS->FreePool (mRomImageTable); + } + + mRomImageTable = TempMapping; + } + + mRomImageTable[mNumberOfPciRomImages].ImageHandle = ImageHandle; + mRomImageTable[mNumberOfPciRomImages].Seg = Seg; + mRomImageTable[mNumberOfPciRomImages].Bus = Bus; + mRomImageTable[mNumberOfPciRomImages].Dev = Dev; + mRomImageTable[mNumberOfPciRomImages].Func = Func; + mNumberOfPciRomImages++; +} + +VOID +HexToString ( + CHAR16 *String, + UINTN Value, + UINTN Digits + ) + +{ + for (; Digits > 0; Digits--, String++) { + *String = mHexDigit[((Value >> (4*(Digits-1))) & 0x0f)]; + } +} + +EFI_STATUS +PciRomLoadEfiDriversFromRomImage ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_PCI_OPTION_ROM_DESCRIPTOR *PciOptionRomDescriptor + ) +/*++ + +Routine Description: + Command entry point. + +Arguments: + ImageHandle The image handle. + SystemTable The system table. + +Returns: + EFI_SUCCESS - The command completed successfully + EFI_INVALID_PARAMETER - Command usage error + EFI_UNSUPPORTED - Protocols unsupported + EFI_OUT_OF_RESOURCES - Out of memory + Other value - Unknown error + +--*/ +{ + VOID *RomBar; + UINTN RomSize; + CHAR16 *FileName; + EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader; + PCI_DATA_STRUCTURE *Pcir; + UINTN ImageIndex; + UINTN RomBarOffset; + UINT32 ImageSize; + UINT16 ImageOffset; + EFI_HANDLE ImageHandle; + EFI_STATUS Status; + EFI_STATUS retStatus; + EFI_DEVICE_PATH_PROTOCOL *FilePath; + BOOLEAN SkipImage; + UINT32 DestinationSize; + UINT32 ScratchSize; + UINT8 *Scratch; + VOID *ImageBuffer; + VOID *DecompressedImageBuffer; + UINT32 ImageLength; + EFI_DECOMPRESS_PROTOCOL *Decompress; + UINT32 InitializationSize; + + RomBar = (VOID *) (UINTN) PciOptionRomDescriptor->RomAddress; + RomSize = (UINTN) PciOptionRomDescriptor->RomLength; + FileName = L"PciRom Seg=00000000 Bus=00 Dev=00 Func=00 Image=0000"; + + HexToString (&FileName[11], PciOptionRomDescriptor->Seg, 8); + HexToString (&FileName[24], PciOptionRomDescriptor->Bus, 2); + HexToString (&FileName[31], PciOptionRomDescriptor->Dev, 2); + HexToString (&FileName[39], PciOptionRomDescriptor->Func, 2); + + ImageIndex = 0; + retStatus = EFI_NOT_FOUND; + RomBarOffset = (UINTN) RomBar; + + do { + + EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) (UINTN) RomBarOffset; + + + if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) { + return retStatus; + } + + // + // If the pointer to the PCI Data Structure is invalid, no further images can be located. + // The PCI Data Structure must be DWORD aligned. + // + if (EfiRomHeader->PcirOffset == 0 || + (EfiRomHeader->PcirOffset & 3) != 0 || + RomBarOffset - (UINTN)RomBar + EfiRomHeader->PcirOffset + sizeof (PCI_DATA_STRUCTURE) > RomSize) { + break; + } + Pcir = (PCI_DATA_STRUCTURE *) (UINTN) (RomBarOffset + EfiRomHeader->PcirOffset); + // + // If a valid signature is not present in the PCI Data Structure, no further images can be located. + // + if (Pcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) { + break; + } + ImageSize = Pcir->ImageLength * 512; + if (RomBarOffset - (UINTN)RomBar + ImageSize > RomSize) { + break; + } + + if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) && + (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) && + ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) || + (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER))) { + + ImageOffset = EfiRomHeader->EfiImageHeaderOffset; + InitializationSize = EfiRomHeader->InitializationSize * 512; + + if (InitializationSize <= ImageSize && ImageOffset < InitializationSize) { + + ImageBuffer = (VOID *) (UINTN) (RomBarOffset + ImageOffset); + ImageLength = InitializationSize - ImageOffset; + DecompressedImageBuffer = NULL; + + // + // decompress here if needed + // + SkipImage = FALSE; + if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) { + SkipImage = TRUE; + } + + if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) { + Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress); + if (EFI_ERROR (Status)) { + SkipImage = TRUE; + } else { + SkipImage = TRUE; + Status = Decompress->GetInfo ( + Decompress, + ImageBuffer, + ImageLength, + &DestinationSize, + &ScratchSize + ); + if (!EFI_ERROR (Status)) { + DecompressedImageBuffer = NULL; + DecompressedImageBuffer = AllocatePool (DestinationSize); + if (DecompressedImageBuffer != NULL) { + Scratch = AllocatePool (ScratchSize); + if (Scratch != NULL) { + Status = Decompress->Decompress ( + Decompress, + ImageBuffer, + ImageLength, + DecompressedImageBuffer, + DestinationSize, + Scratch, + ScratchSize + ); + if (!EFI_ERROR (Status)) { + ImageBuffer = DecompressedImageBuffer; + ImageLength = DestinationSize; + SkipImage = FALSE; + } + + gBS->FreePool (Scratch); + } + } + } + } + } + + if (!SkipImage) { + + // + // load image and start image + // + + HexToString (&FileName[48], ImageIndex, 4); + FilePath = FileDevicePath (NULL, FileName); + + Status = gBS->LoadImage ( + FALSE, + This->ImageHandle, + FilePath, + ImageBuffer, + ImageLength, + &ImageHandle + ); + if (!EFI_ERROR (Status)) { + Status = gBS->StartImage (ImageHandle, NULL, NULL); + if (!EFI_ERROR (Status)) { + PciRomAddImageMapping ( + ImageHandle, + PciOptionRomDescriptor->Seg, + PciOptionRomDescriptor->Bus, + PciOptionRomDescriptor->Dev, + PciOptionRomDescriptor->Func + ); + retStatus = Status; + } + } + if (FilePath != NULL) { + gBS->FreePool (FilePath); + } + } + + if (DecompressedImageBuffer != NULL) { + gBS->FreePool (DecompressedImageBuffer); + } + + } + } + + RomBarOffset = RomBarOffset + ImageSize; + ImageIndex++; + } while (((Pcir->Indicator & 0x80) == 0x00) && ((RomBarOffset - (UINTN) RomBar) < RomSize)); + + return retStatus; +} + +EFI_STATUS +PciRomLoadEfiDriversFromOptionRomTable ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + EFI_STATUS Status; + EFI_PCI_OPTION_ROM_TABLE *PciOptionRomTable; + EFI_PCI_OPTION_ROM_DESCRIPTOR *PciOptionRomDescriptor; + UINTN Index; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; + UINT16 MinBus; + UINT16 MaxBus; + + Status = EfiGetSystemConfigurationTable (&gEfiPciOptionRomTableGuid, (VOID **) &PciOptionRomTable); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + Status = EFI_NOT_FOUND; + + for (Index = 0; Index < PciOptionRomTable->PciOptionRomCount; Index++) { + PciOptionRomDescriptor = &PciOptionRomTable->PciOptionRomDescriptors[Index]; + if (!PciOptionRomDescriptor->DontLoadEfiRom) { + if (PciOptionRomDescriptor->Seg == PciRootBridgeIo->SegmentNumber) { + Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors); + if (EFI_ERROR (Status)) { + return Status; + } + + PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL); + if ((MinBus <= PciOptionRomDescriptor->Bus) && (PciOptionRomDescriptor->Bus <= MaxBus)) { + Status = PciRomLoadEfiDriversFromRomImage (This, PciOptionRomDescriptor); + PciOptionRomDescriptor->DontLoadEfiRom |= 2; + } + } + } + } + + return Status; +} + +EFI_STATUS +PciRomGetRomResourceFromPciOptionRomTable ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + +--*/ +{ + EFI_STATUS Status; + EFI_PCI_OPTION_ROM_TABLE *PciOptionRomTable; + EFI_PCI_OPTION_ROM_DESCRIPTOR *PciOptionRomDescriptor; + UINTN Index; + + Status = EfiGetSystemConfigurationTable (&gEfiPciOptionRomTableGuid, (VOID **) &PciOptionRomTable); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + for (Index = 0; Index < PciOptionRomTable->PciOptionRomCount; Index++) { + PciOptionRomDescriptor = &PciOptionRomTable->PciOptionRomDescriptors[Index]; + if (PciOptionRomDescriptor->Seg == PciRootBridgeIo->SegmentNumber && + PciOptionRomDescriptor->Bus == PciIoDevice->BusNumber && + PciOptionRomDescriptor->Dev == PciIoDevice->DeviceNumber && + PciOptionRomDescriptor->Func == PciIoDevice->FunctionNumber ) { + + PciIoDevice->PciIo.RomImage = (VOID *) (UINTN) PciOptionRomDescriptor->RomAddress; + PciIoDevice->PciIo.RomSize = (UINTN) PciOptionRomDescriptor->RomLength; + } + } + + for (Index = 0; Index < mNumberOfPciRomImages; Index++) { + if (mRomImageTable[Index].Seg == PciRootBridgeIo->SegmentNumber && + mRomImageTable[Index].Bus == PciIoDevice->BusNumber && + mRomImageTable[Index].Dev == PciIoDevice->DeviceNumber && + mRomImageTable[Index].Func == PciIoDevice->FunctionNumber ) { + + AddDriver (PciIoDevice, mRomImageTable[Index].ImageHandle); + } + } + + return EFI_SUCCESS; +} diff --git a/CorebootModulePkg/PciBusNoEnumerationDxe/PciRomTable.h b/CorebootModulePkg/PciBusNoEnumerationDxe/PciRomTable.h new file mode 100644 index 0000000000..773fe80f37 --- /dev/null +++ b/CorebootModulePkg/PciBusNoEnumerationDxe/PciRomTable.h @@ -0,0 +1,58 @@ +/*++ + +Copyright (c) 2005 - 2006, 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: + + PciRomTable.h + +Abstract: + + Option Rom Support for PCI Bus Driver + +Revision History + +--*/ + +#ifndef _EFI_PCI_ROM_TABLE_H +#define _EFI_PCI_ROM_TABLE_H + + +EFI_STATUS +PciRomLoadEfiDriversFromOptionRomTable ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo + ); + +EFI_STATUS +PciRomGetRomResourceFromPciOptionRomTable ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + This - TODO: add argument description + PciRootBridgeIo - TODO: add argument description + PciIoDevice - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +; +#endif diff --git a/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/DeviceIo.c b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/DeviceIo.c new file mode 100644 index 0000000000..e924b44dcd --- /dev/null +++ b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/DeviceIo.c @@ -0,0 +1,845 @@ +/*++ + +Copyright (c) 2006 - 2012, 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: + + DeviceIo.c + +Abstract: + + EFI PC-AT PCI Device IO driver + +--*/ +#include "PcatPciRootBridge.h" +#include "DeviceIo.h" + +EFI_STATUS +DeviceIoConstructor ( + IN EFI_HANDLE Handle, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN UINT16 PrimaryBus, + IN UINT16 SubordinateBus + ) +/*++ + +Routine Description: + + Initialize and install a Device IO protocol on a empty device path handle. + +Arguments: + + Handle - Handle of PCI RootBridge IO instance + PciRootBridgeIo - PCI RootBridge IO instance + DevicePath - Device Path of PCI RootBridge IO instance + PrimaryBus - Primary Bus + SubordinateBus - Subordinate Bus + +Returns: + + EFI_SUCCESS - This driver is added to ControllerHandle. + EFI_ALREADY_STARTED - This driver is already running on ControllerHandle. + Others - This driver does not support this device. + +--*/ +{ + EFI_STATUS Status; + DEVICE_IO_PRIVATE_DATA *Private; + + // + // Initialize the Device IO device instance. + // + Private = AllocateZeroPool (sizeof (DEVICE_IO_PRIVATE_DATA)); + if (Private == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Private->Signature = DEVICE_IO_PRIVATE_DATA_SIGNATURE; + Private->Handle = Handle; + Private->PciRootBridgeIo = PciRootBridgeIo; + Private->DevicePath = DevicePath; + Private->PrimaryBus = PrimaryBus; + Private->SubordinateBus = SubordinateBus; + + Private->DeviceIo.Mem.Read = DeviceIoMemRead; + Private->DeviceIo.Mem.Write = DeviceIoMemWrite; + Private->DeviceIo.Io.Read = DeviceIoIoRead; + Private->DeviceIo.Io.Write = DeviceIoIoWrite; + Private->DeviceIo.Pci.Read = DeviceIoPciRead; + Private->DeviceIo.Pci.Write = DeviceIoPciWrite; + Private->DeviceIo.PciDevicePath = DeviceIoPciDevicePath; + Private->DeviceIo.Map = DeviceIoMap; + Private->DeviceIo.Unmap = DeviceIoUnmap; + Private->DeviceIo.AllocateBuffer = DeviceIoAllocateBuffer; + Private->DeviceIo.Flush = DeviceIoFlush; + Private->DeviceIo.FreeBuffer = DeviceIoFreeBuffer; + + // + // Install protocol interfaces for the Device IO device. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &Private->Handle, + &gEfiDeviceIoProtocolGuid, + &Private->DeviceIo, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +EFI_STATUS +EFIAPI +DeviceIoMemRead ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform reading memory mapped I/O space of device. + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The destination buffer to store results. + +Returns: + + EFI_SUCCESS - The data was read from the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +{ + EFI_STATUS Status; + DEVICE_IO_PRIVATE_DATA *Private; + + Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This); + + if (Width > MMIO_COPY_UINT64) { + return EFI_INVALID_PARAMETER; + } + if (Width >= MMIO_COPY_UINT8) { + Width = (EFI_IO_WIDTH) (Width - MMIO_COPY_UINT8); + Status = Private->PciRootBridgeIo->CopyMem ( + Private->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + (UINT64)(UINTN) Buffer, + Address, + Count + ); + } else { + Status = Private->PciRootBridgeIo->Mem.Read ( + Private->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Address, + Count, + Buffer + ); + } + + return Status; +} + + + +EFI_STATUS +EFIAPI +DeviceIoMemWrite ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform writing memory mapped I/O space of device. + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The source buffer of data to be written. + +Returns: + + EFI_SUCCESS - The data was written to the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +{ + EFI_STATUS Status; + DEVICE_IO_PRIVATE_DATA *Private; + + Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This); + + if (Width > MMIO_COPY_UINT64) { + return EFI_INVALID_PARAMETER; + } + if (Width >= MMIO_COPY_UINT8) { + Width = (EFI_IO_WIDTH) (Width - MMIO_COPY_UINT8); + Status = Private->PciRootBridgeIo->CopyMem ( + Private->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Address, + (UINT64)(UINTN) Buffer, + Count + ); + } else { + Status = Private->PciRootBridgeIo->Mem.Write ( + Private->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Address, + Count, + Buffer + ); + } + + return Status; +} + +EFI_STATUS +EFIAPI +DeviceIoIoRead ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform reading I/O space of device. + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The destination buffer to store results. + +Returns: + + EFI_SUCCESS - The data was read from the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +{ + EFI_STATUS Status; + DEVICE_IO_PRIVATE_DATA *Private; + + Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This); + + if (Width >= MMIO_COPY_UINT8) { + return EFI_INVALID_PARAMETER; + } + + Status = Private->PciRootBridgeIo->Io.Read ( + Private->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Address, + Count, + Buffer + ); + + return Status; +} + +EFI_STATUS +EFIAPI +DeviceIoIoWrite ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform writing I/O space of device. + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The source buffer of data to be written. + +Returns: + + EFI_SUCCESS - The data was written to the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +{ + EFI_STATUS Status; + DEVICE_IO_PRIVATE_DATA *Private; + + Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This); + + if (Width >= MMIO_COPY_UINT8) { + return EFI_INVALID_PARAMETER; + } + + Status = Private->PciRootBridgeIo->Io.Write ( + Private->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Address, + Count, + Buffer + ); + + return Status; +} + +EFI_STATUS +EFIAPI +DeviceIoPciRead ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform reading PCI configuration space of device + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The destination buffer to store results. + +Returns: + + EFI_SUCCESS - The data was read from the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +{ + EFI_STATUS Status; + DEVICE_IO_PRIVATE_DATA *Private; + + Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This); + + if ((UINT32)Width >= MMIO_COPY_UINT8) { + return EFI_INVALID_PARAMETER; + } + + Status = Private->PciRootBridgeIo->Pci.Read ( + Private->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Address, + Count, + Buffer + ); + + return Status; +} + +EFI_STATUS +EFIAPI +DeviceIoPciWrite ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform writing PCI configuration space of device. + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The source buffer of data to be written. + +Returns: + + EFI_SUCCESS - The data was written to the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +{ + EFI_STATUS Status; + DEVICE_IO_PRIVATE_DATA *Private; + + Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This); + + if ((UINT32)Width >= MMIO_COPY_UINT8) { + return EFI_INVALID_PARAMETER; + } + + Status = Private->PciRootBridgeIo->Pci.Write ( + Private->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Address, + Count, + Buffer + ); + + return Status; +} + +EFI_DEVICE_PATH_PROTOCOL * +AppendPciDevicePath ( + IN DEVICE_IO_PRIVATE_DATA *Private, + IN UINT8 Bus, + IN UINT8 Device, + IN UINT8 Function, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN OUT UINT16 *BridgePrimaryBus, + IN OUT UINT16 *BridgeSubordinateBus + ) +/*++ + +Routine Description: + + Append a PCI device path node to another device path. + +Arguments: + + Private - A pointer to DEVICE_IO_PRIVATE_DATA instance. + Bus - PCI bus number of the device. + Device - PCI device number of the device. + Function - PCI function number of the device. + DevicePath - Original device path which will be appended a PCI device path node. + BridgePrimaryBus - Primary bus number of the bridge. + BridgeSubordinateBus - Subordinate bus number of the bridge. + +Returns: + + Pointer to the appended PCI device path. + +--*/ +{ + UINT16 ThisBus; + UINT8 ThisDevice; + UINT8 ThisFunc; + UINT64 Address; + PCI_TYPE01 PciBridge; + PCI_TYPE01 *PciPtr; + EFI_DEVICE_PATH_PROTOCOL *ReturnDevicePath; + PCI_DEVICE_PATH PciNode; + + PciPtr = &PciBridge; + for (ThisBus = *BridgePrimaryBus; ThisBus <= *BridgeSubordinateBus; ThisBus++) { + for (ThisDevice = 0; ThisDevice <= PCI_MAX_DEVICE; ThisDevice++) { + for (ThisFunc = 0; ThisFunc <= PCI_MAX_FUNC; ThisFunc++) { + Address = EFI_PCI_ADDRESS (ThisBus, ThisDevice, ThisFunc, 0); + ZeroMem (PciPtr, sizeof (PCI_TYPE01)); + Private->DeviceIo.Pci.Read ( + &Private->DeviceIo, + IO_UINT32, + Address, + 1, + &(PciPtr->Hdr.VendorId) + ); + if ((PciPtr->Hdr.VendorId == 0xffff) && (ThisFunc == 0)) { + break; + } + if (PciPtr->Hdr.VendorId == 0xffff) { + continue; + } + + Private->DeviceIo.Pci.Read ( + &Private->DeviceIo, + IO_UINT32, + Address, + sizeof (PCI_TYPE01) / sizeof (UINT32), + PciPtr + ); + if (IS_PCI_BRIDGE (PciPtr)) { + if (Bus >= PciPtr->Bridge.SecondaryBus && Bus <= PciPtr->Bridge.SubordinateBus) { + + PciNode.Header.Type = HARDWARE_DEVICE_PATH; + PciNode.Header.SubType = HW_PCI_DP; + SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode)); + + PciNode.Device = ThisDevice; + PciNode.Function = ThisFunc; + ReturnDevicePath = AppendDevicePathNode (DevicePath, &PciNode.Header); + + *BridgePrimaryBus = PciPtr->Bridge.SecondaryBus; + *BridgeSubordinateBus = PciPtr->Bridge.SubordinateBus; + return ReturnDevicePath; + } + } + + if ((ThisFunc == 0) && ((PciPtr->Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x0)) { + // + // Skip sub functions, this is not a multi function device + // + break; + } + } + } + } + + ZeroMem (&PciNode, sizeof (PciNode)); + PciNode.Header.Type = HARDWARE_DEVICE_PATH; + PciNode.Header.SubType = HW_PCI_DP; + SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode)); + PciNode.Device = Device; + PciNode.Function = Function; + + ReturnDevicePath = AppendDevicePathNode (DevicePath, &PciNode.Header); + + *BridgePrimaryBus = 0xffff; + *BridgeSubordinateBus = 0xffff; + return ReturnDevicePath; +} + +EFI_STATUS +EFIAPI +DeviceIoPciDevicePath ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN UINT64 Address, + IN OUT EFI_DEVICE_PATH_PROTOCOL **PciDevicePath + ) +/*++ + +Routine Description: + + Provides an EFI Device Path for a PCI device with the given PCI configuration space address. + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + Address - The PCI configuration space address of the device whose Device Path + is going to be returned. + PciDevicePath - A pointer to the pointer for the EFI Device Path for PciAddress. + Memory for the Device Path is allocated from the pool. + +Returns: + + EFI_SUCCESS - The PciDevicePath returns a pointer to a valid EFI Device Path. + EFI_UNSUPPORTED - The PciAddress does not map to a valid EFI Device Path. + EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources. + +--*/ +{ + DEVICE_IO_PRIVATE_DATA *Private; + UINT16 PrimaryBus; + UINT16 SubordinateBus; + UINT8 Bus; + UINT8 Device; + UINT8 Func; + + Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This); + + Bus = (UINT8) (((UINT32) Address >> 24) & 0xff); + Device = (UINT8) (((UINT32) Address >> 16) & 0xff); + Func = (UINT8) (((UINT32) Address >> 8) & 0xff); + + if (Bus < Private->PrimaryBus || Bus > Private->SubordinateBus) { + return EFI_UNSUPPORTED; + } + + *PciDevicePath = Private->DevicePath; + PrimaryBus = Private->PrimaryBus; + SubordinateBus = Private->SubordinateBus; + do { + *PciDevicePath = AppendPciDevicePath ( + Private, + Bus, + Device, + Func, + *PciDevicePath, + &PrimaryBus, + &SubordinateBus + ); + if (*PciDevicePath == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } while (PrimaryBus != 0xffff); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DeviceIoMap ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_OPERATION_TYPE Operation, + IN EFI_PHYSICAL_ADDRESS *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +/*++ + +Routine Description: + + Provides the device-specific addresses needed to access system memory. + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + Operation - Indicates if the bus master is going to read or write to system memory. + HostAddress - The system memory address to map to the device. + NumberOfBytes - On input the number of bytes to map. On output the number of bytes + that were mapped. + DeviceAddress - The resulting map address for the bus master device to use to access the + hosts HostAddress. + Mapping - A resulting value to pass to Unmap(). + +Returns: + + EFI_SUCCESS - The range was mapped for the returned NumberOfBytes. + EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined. + EFI_UNSUPPORTED - The HostAddress cannot be mapped as a common buffer. + EFI_DEVICE_ERROR - The system hardware could not map the requested address. + EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources. + +--*/ +{ + EFI_STATUS Status; + DEVICE_IO_PRIVATE_DATA *Private; + + Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This); + + if ((UINT32)Operation > EfiBusMasterCommonBuffer) { + return EFI_INVALID_PARAMETER; + } + + if (((UINTN) (*HostAddress) != (*HostAddress)) && Operation == EfiBusMasterCommonBuffer) { + return EFI_UNSUPPORTED; + } + + Status = Private->PciRootBridgeIo->Map ( + Private->PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) Operation, + (VOID *) (UINTN) (*HostAddress), + NumberOfBytes, + DeviceAddress, + Mapping + ); + + return Status; +} + +EFI_STATUS +EFIAPI +DeviceIoUnmap ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN VOID *Mapping + ) +/*++ + +Routine Description: + + Completes the Map() operation and releases any corresponding resources. + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + Mapping - The mapping value returned from Map(). + +Returns: + + EFI_SUCCESS - The range was unmapped. + EFI_DEVICE_ERROR - The data was not committed to the target system memory. + +--*/ +{ + EFI_STATUS Status; + DEVICE_IO_PRIVATE_DATA *Private; + + Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This); + + Status = Private->PciRootBridgeIo->Unmap ( + Private->PciRootBridgeIo, + Mapping + ); + + return Status; +} + +EFI_STATUS +EFIAPI +DeviceIoAllocateBuffer ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN OUT EFI_PHYSICAL_ADDRESS *PhysicalAddress + ) +/*++ + +Routine Description: + + Allocates pages that are suitable for an EFIBusMasterCommonBuffer mapping. + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + Type - The type allocation to perform. + MemoryType - The type of memory to allocate, EfiBootServicesData or + EfiRuntimeServicesData. + Pages - The number of pages to allocate. + PhysicalAddress - A pointer to store the base address of the allocated range. + +Returns: + + EFI_SUCCESS - The requested memory pages were allocated. + EFI_OUT_OF_RESOURCES - The memory pages could not be allocated. + EFI_INVALID_PARAMETER - The requested memory type is invalid. + EFI_UNSUPPORTED - The requested PhysicalAddress is not supported on + this platform. + +--*/ +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS HostAddress; + + HostAddress = *PhysicalAddress; + + if ((MemoryType != EfiBootServicesData) && (MemoryType != EfiRuntimeServicesData)) { + return EFI_INVALID_PARAMETER; + } + + if ((UINT32)Type >= MaxAllocateType) { + return EFI_INVALID_PARAMETER; + } + + if ((Type == AllocateAddress) && (HostAddress + EFI_PAGES_TO_SIZE (Pages) - 1 > MAX_COMMON_BUFFER)) { + return EFI_UNSUPPORTED; + } + + if ((AllocateAnyPages == Type) || (AllocateMaxAddress == Type && HostAddress > MAX_COMMON_BUFFER)) { + Type = AllocateMaxAddress; + HostAddress = MAX_COMMON_BUFFER; + } + + Status = gBS->AllocatePages ( + Type, + MemoryType, + Pages, + &HostAddress + ); + if (EFI_ERROR (Status)) { + return Status; + } + + + *PhysicalAddress = HostAddress; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +DeviceIoFlush ( + IN EFI_DEVICE_IO_PROTOCOL *This + ) +/*++ + +Routine Description: + + Flushes any posted write data to the device. + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + +Returns: + + EFI_SUCCESS - The buffers were flushed. + EFI_DEVICE_ERROR - The buffers were not flushed due to a hardware error. + +--*/ +{ + EFI_STATUS Status; + DEVICE_IO_PRIVATE_DATA *Private; + + Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This); + + Status = Private->PciRootBridgeIo->Flush (Private->PciRootBridgeIo); + + return Status; +} + +EFI_STATUS +EFIAPI +DeviceIoFreeBuffer ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN UINTN Pages, + IN EFI_PHYSICAL_ADDRESS HostAddress + ) +/*++ + +Routine Description: + + Frees pages that were allocated with AllocateBuffer(). + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + Pages - The number of pages to free. + HostAddress - The base address of the range to free. + +Returns: + + EFI_SUCCESS - The requested memory pages were freed. + EFI_NOT_FOUND - The requested memory pages were not allocated with + AllocateBuffer(). + EFI_INVALID_PARAMETER - HostAddress is not page aligned or Pages is invalid. + +--*/ +{ + if (((HostAddress & EFI_PAGE_MASK) != 0) || (Pages <= 0)) { + return EFI_INVALID_PARAMETER; + } + + return gBS->FreePages (HostAddress, Pages); +} diff --git a/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/DeviceIo.h b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/DeviceIo.h new file mode 100644 index 0000000000..9b483743da --- /dev/null +++ b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/DeviceIo.h @@ -0,0 +1,449 @@ +/*++ + +Copyright (c) 2006, 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: + + DeviceIo.h + +Abstract: + + Private Data definition for Device IO driver + +--*/ + +#ifndef _DEVICE_IO_H +#define _DEVICE_IO_H + + + +#define DEVICE_IO_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('d', 'e', 'v', 'I') + +#define MAX_COMMON_BUFFER 0x00000000FFFFFFFF + +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + EFI_DEVICE_IO_PROTOCOL DeviceIo; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINT16 PrimaryBus; + UINT16 SubordinateBus; +} DEVICE_IO_PRIVATE_DATA; + +#define DEVICE_IO_PRIVATE_DATA_FROM_THIS(a) CR (a, DEVICE_IO_PRIVATE_DATA, DeviceIo, DEVICE_IO_PRIVATE_DATA_SIGNATURE) + +EFI_STATUS +DeviceIoConstructor ( + IN EFI_HANDLE Handle, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN UINT16 PrimaryBus, + IN UINT16 SubordinateBus + ) +/*++ + +Routine Description: + + Initialize and install a Device IO protocol on a empty device path handle. + +Arguments: + + Handle - Handle of PCI RootBridge IO instance + PciRootBridgeIo - PCI RootBridge IO instance + DevicePath - Device Path of PCI RootBridge IO instance + PrimaryBus - Primary Bus + SubordinateBus - Subordinate Bus + +Returns: + + EFI_SUCCESS - This driver is added to ControllerHandle. + EFI_ALREADY_STARTED - This driver is already running on ControllerHandle. + Others - This driver does not support this device. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoMemRead ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform reading memory mapped I/O space of device. + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The destination buffer to store results. + +Returns: + + EFI_SUCCESS - The data was read from the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoMemWrite ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform writing memory mapped I/O space of device. + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The source buffer of data to be written. + +Returns: + + EFI_SUCCESS - The data was written to the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoIoRead ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform reading I/O space of device. + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The destination buffer to store results. + +Returns: + + EFI_SUCCESS - The data was read from the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoIoWrite ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform writing I/O space of device. + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The source buffer of data to be written. + +Returns: + + EFI_SUCCESS - The data was written to the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoPciRead ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform reading PCI configuration space of device + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The destination buffer to store results. + +Returns: + + EFI_SUCCESS - The data was read from the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoPciWrite ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +/*++ + +Routine Description: + + Perform writing PCI configuration space of device. + +Arguments: + + This - A pointer to EFI_DEVICE_IO protocol instance. + Width - Width of I/O operations. + Address - The base address of I/O operations. + Count - The number of I/O operations to perform. + Bytes moves is Width size * Count, starting at Address. + Buffer - The source buffer of data to be written. + +Returns: + + EFI_SUCCESS - The data was written to the device. + EFI_INVALID_PARAMETER - Width is invalid. + EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoPciDevicePath ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN UINT64 Address, + IN OUT EFI_DEVICE_PATH_PROTOCOL **PciDevicePath + ) +/*++ + +Routine Description: + + Append a PCI device path node to another device path. + +Arguments: + + This - A pointer to EFI_DEVICE_IO_PROTOCOL. + Address - PCI bus,device, function. + PciDevicePath - PCI device path. + +Returns: + + Pointer to the appended PCI device path. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoMap ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_IO_OPERATION_TYPE Operation, + IN EFI_PHYSICAL_ADDRESS *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +/*++ + +Routine Description: + + Provides the device-specific addresses needed to access system memory. + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + Operation - Indicates if the bus master is going to read or write to system memory. + HostAddress - The system memory address to map to the device. + NumberOfBytes - On input the number of bytes to map. On output the number of bytes + that were mapped. + DeviceAddress - The resulting map address for the bus master device to use to access the + hosts HostAddress. + Mapping - A resulting value to pass to Unmap(). + +Returns: + + EFI_SUCCESS - The range was mapped for the returned NumberOfBytes. + EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined. + EFI_UNSUPPORTED - The HostAddress cannot be mapped as a common buffer. + EFI_DEVICE_ERROR - The system hardware could not map the requested address. + EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoUnmap ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN VOID *Mapping + ) +/*++ + +Routine Description: + + Completes the Map() operation and releases any corresponding resources. + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + Mapping - The mapping value returned from Map(). + +Returns: + + EFI_SUCCESS - The range was unmapped. + EFI_DEVICE_ERROR - The data was not committed to the target system memory. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoAllocateBuffer ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN OUT EFI_PHYSICAL_ADDRESS *HostAddress + ) +/*++ + +Routine Description: + + Allocates pages that are suitable for an EFIBusMasterCommonBuffer mapping. + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + Type - The type allocation to perform. + MemoryType - The type of memory to allocate, EfiBootServicesData or + EfiRuntimeServicesData. + Pages - The number of pages to allocate. + HostAddress - A pointer to store the base address of the allocated range. + +Returns: + + EFI_SUCCESS - The requested memory pages were allocated. + EFI_OUT_OF_RESOURCES - The memory pages could not be allocated. + EFI_INVALID_PARAMETER - The requested memory type is invalid. + EFI_UNSUPPORTED - The requested PhysicalAddress is not supported on + this platform. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoFlush ( + IN EFI_DEVICE_IO_PROTOCOL *This + ) +/*++ + +Routine Description: + + Flushes any posted write data to the device. + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + +Returns: + + EFI_SUCCESS - The buffers were flushed. + EFI_DEVICE_ERROR - The buffers were not flushed due to a hardware error. + +--*/ +; + +EFI_STATUS +EFIAPI +DeviceIoFreeBuffer ( + IN EFI_DEVICE_IO_PROTOCOL *This, + IN UINTN Pages, + IN EFI_PHYSICAL_ADDRESS HostAddress + ) +/*++ + +Routine Description: + + Frees pages that were allocated with AllocateBuffer(). + +Arguments: + + This - A pointer to the EFI_DEVICE_IO_INTERFACE instance. + Pages - The number of pages to free. + HostAddress - The base address of the range to free. + +Returns: + + EFI_SUCCESS - The requested memory pages were freed. + EFI_NOT_FOUND - The requested memory pages were not allocated with + AllocateBuffer(). + EFI_INVALID_PARAMETER - HostAddress is not page aligned or Pages is invalid. + +--*/ +; + +#endif + diff --git a/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/Ia32/PcatIo.c b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/Ia32/PcatIo.c new file mode 100644 index 0000000000..63ea892044 --- /dev/null +++ b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/Ia32/PcatIo.c @@ -0,0 +1,738 @@ +/*++ + +Copyright (c) 2005 - 2012, 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: + PcatPciRootBridgeIo.c + +Abstract: + + EFI PC AT PCI Root Bridge Io Protocol + +Revision History + +--*/ + +#include "PcatPciRootBridge.h" + +BOOLEAN mPciOptionRomTableInstalled = FALSE; +EFI_PCI_OPTION_ROM_TABLE mPciOptionRomTable = {0, NULL}; + +EFI_STATUS +EFIAPI +PcatRootBridgeIoIoRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + return gCpuIo->Io.Read ( + gCpuIo, + (EFI_CPU_IO_PROTOCOL_WIDTH) Width, + UserAddress, + Count, + UserBuffer + ); +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoIoWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + return gCpuIo->Io.Write ( + gCpuIo, + (EFI_CPU_IO_PROTOCOL_WIDTH) Width, + UserAddress, + Count, + UserBuffer + ); + +} + +EFI_STATUS +PcatRootBridgeIoGetIoPortMapping ( + OUT EFI_PHYSICAL_ADDRESS *IoPortMapping, + OUT EFI_PHYSICAL_ADDRESS *MemoryPortMapping + ) +/*++ + + Get the IO Port Mapping. For IA-32 it is always 0. + +--*/ +{ + *IoPortMapping = 0; + *MemoryPortMapping = 0; + + return EFI_SUCCESS; +} + +EFI_STATUS +PcatRootBridgeIoPciRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN BOOLEAN Write, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + PCI_CONFIG_ACCESS_CF8 Pci; + PCI_CONFIG_ACCESS_CF8 PciAligned; + UINT32 InStride; + UINT32 OutStride; + UINTN PciData; + UINTN PciDataStride; + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress; + UINT64 PciExpressRegAddr; + BOOLEAN UsePciExpressAccess; + + if ((UINT32)Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + if ((Width & 0x03) >= EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + InStride = 1 << (Width & 0x03); + OutStride = InStride; + if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + InStride = 0; + } + + if (Width >= EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) { + OutStride = 0; + } + + UsePciExpressAccess = FALSE; + + CopyMem (&PciAddress, &UserAddress, sizeof(UINT64)); + + if (PciAddress.ExtendedRegister > 0xFF) { + // + // Check PciExpressBaseAddress + // + if ((PrivateData->PciExpressBaseAddress == 0) || + (PrivateData->PciExpressBaseAddress >= MAX_ADDRESS)) { + return EFI_UNSUPPORTED; + } else { + UsePciExpressAccess = TRUE; + } + } else { + if (PciAddress.ExtendedRegister != 0) { + Pci.Bits.Reg = PciAddress.ExtendedRegister & 0xFF; + } else { + Pci.Bits.Reg = PciAddress.Register; + } + // + // Note: We can also use PciExpress access here, if wanted. + // + } + + if (!UsePciExpressAccess) { + Pci.Bits.Func = PciAddress.Function; + Pci.Bits.Dev = PciAddress.Device; + Pci.Bits.Bus = PciAddress.Bus; + Pci.Bits.Reserved = 0; + Pci.Bits.Enable = 1; + + // + // PCI Config access are all 32-bit alligned, but by accessing the + // CONFIG_DATA_REGISTER (0xcfc) with different widths more cycle types + // are possible on PCI. + // + // To read a byte of PCI config space you load 0xcf8 and + // read 0xcfc, 0xcfd, 0xcfe, 0xcff + // + PciDataStride = Pci.Bits.Reg & 0x03; + + while (Count) { + PciAligned = Pci; + PciAligned.Bits.Reg &= 0xfc; + PciData = (UINTN)PrivateData->PciData + PciDataStride; + EfiAcquireLock(&PrivateData->PciLock); + This->Io.Write (This, EfiPciWidthUint32, PrivateData->PciAddress, 1, &PciAligned); + if (Write) { + This->Io.Write (This, Width, PciData, 1, UserBuffer); + } else { + This->Io.Read (This, Width, PciData, 1, UserBuffer); + } + EfiReleaseLock(&PrivateData->PciLock); + UserBuffer = ((UINT8 *)UserBuffer) + OutStride; + PciDataStride = (PciDataStride + InStride) % 4; + Pci.Bits.Reg += InStride; + Count -= 1; + } + } else { + // + // Access PCI-Express space by using memory mapped method. + // + PciExpressRegAddr = (PrivateData->PciExpressBaseAddress) | + (PciAddress.Bus << 20) | + (PciAddress.Device << 15) | + (PciAddress.Function << 12); + if (PciAddress.ExtendedRegister != 0) { + PciExpressRegAddr += PciAddress.ExtendedRegister; + } else { + PciExpressRegAddr += PciAddress.Register; + } + while (Count) { + if (Write) { + This->Mem.Write (This, Width, (UINTN) PciExpressRegAddr, 1, UserBuffer); + } else { + This->Mem.Read (This, Width, (UINTN) PciExpressRegAddr, 1, UserBuffer); + } + + UserBuffer = ((UINT8 *) UserBuffer) + OutStride; + PciExpressRegAddr += InStride; + Count -= 1; + } + } + + return EFI_SUCCESS; +} + +VOID +ScanPciBus( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + EFI_PCI_BUS_SCAN_CALLBACK Callback, + VOID *Context + ) + +{ + UINT16 Bus; + UINT16 Device; + UINT16 Func; + UINT64 Address; + PCI_TYPE00 PciHeader; + + // + // Loop through all busses + // + for (Bus = MinBus; Bus <= MaxBus; Bus++) { + // + // Loop 32 devices per bus + // + for (Device = MinDevice; Device <= MaxDevice; Device++) { + // + // Loop through 8 functions per device + // + for (Func = MinFunc; Func <= MaxFunc; Func++) { + + // + // Compute the EFI Address required to access the PCI Configuration Header of this PCI Device + // + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0); + + // + // Read the VendorID from this PCI Device's Confioguration Header + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &PciHeader.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 (PciHeader.Hdr.VendorId == 0xffff && Func == 0) { + break; + } + + if (PciHeader.Hdr.VendorId != 0xffff) { + + // + // Read the HeaderType to determine if this is a multi-function device + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint8, Address + 0x0e, 1, &PciHeader.Hdr.HeaderType); + + // + // Call the callback function for the device that was found + // + Callback( + IoDev, + MinBus, MaxBus, + MinDevice, MaxDevice, + MinFunc, MaxFunc, + Bus, + Device, + Func, + Context + ); + + // + // If this is not a multi-function device, we can leave the loop + // to deal with the next device. + // + if ((PciHeader.Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00 && Func == 0) { + break; + } + } + } + } + } +} + +VOID +CheckForRom ( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + UINT16 Bus, + UINT16 Device, + UINT16 Func, + IN VOID *VoidContext + ) +{ + EFI_STATUS Status; + PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context; + UINT64 Address; + PCI_TYPE00 PciHeader; + PCI_TYPE01 *PciBridgeHeader; + UINT32 Register; + UINT32 RomBar; + UINT32 RomBarSize; + EFI_PHYSICAL_ADDRESS RomBuffer; + UINT32 MaxRomSize; + EFI_PCI_EXPANSION_ROM_HEADER EfiRomHeader; + PCI_DATA_STRUCTURE Pcir; + EFI_PCI_OPTION_ROM_DESCRIPTOR *TempPciOptionRomDescriptors; + BOOLEAN LastImage; + + Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext; + + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0); + + // + // Save the contents of the PCI Configuration Header + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader); + + if (IS_PCI_BRIDGE(&PciHeader)) { + + PciBridgeHeader = (PCI_TYPE01 *)(&PciHeader); + + // + // See if the PCI-PCI Bridge has its secondary interface enabled. + // + if (PciBridgeHeader->Bridge.SubordinateBus >= PciBridgeHeader->Bridge.SecondaryBus) { + + // + // Disable the Prefetchable Memory Window + // + Register = 0x00000000; + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x26, 1, &Register); + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x2c, 1, &Register); + Register = 0xffffffff; + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x24, 1, &Register); + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x28, 1, &Register); + + // + // Program Memory Window to the PCI Root Bridge Memory Window + // + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x20, 4, &Context->PpbMemoryWindow); + + // + // Enable the Memory decode for the PCI-PCI Bridge + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + Register |= 0x02; + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + + // + // Recurse on the Secondary Bus Number + // + ScanPciBus( + IoDev, + PciBridgeHeader->Bridge.SecondaryBus, PciBridgeHeader->Bridge.SecondaryBus, + 0, PCI_MAX_DEVICE, + 0, PCI_MAX_FUNC, + CheckForRom, Context + ); + } + } else { + + // + // Check if an Option ROM Register is present and save the Option ROM Window Register + // + RomBar = 0xffffffff; + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); + IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); + + RomBarSize = (~(RomBar & 0xfffff800)) + 1; + + // + // Make sure the size of the ROM is between 0 and 16 MB + // + if (RomBarSize > 0 && RomBarSize <= 0x01000000) { + + // + // Program Option ROM Window Register to the PCI Root Bridge Window and Enable the Option ROM Window + // + RomBar = (Context->PpbMemoryWindow & 0xffff) << 16; + RomBar = ((RomBar - 1) & (~(RomBarSize - 1))) + RomBarSize; + if (RomBar < (Context->PpbMemoryWindow & 0xffff0000)) { + MaxRomSize = (Context->PpbMemoryWindow & 0xffff0000) - RomBar; + RomBar = RomBar + 1; + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); + IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); + RomBar = RomBar - 1; + + // + // Enable the Memory decode for the PCI Device + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + Register |= 0x02; + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + + // + // Follow the chain of images to determine the size of the Option ROM present + // Keep going until the last image is found by looking at the Indicator field + // or the size of an image is 0, or the size of all the images is bigger than the + // size of the window programmed into the PPB. + // + RomBarSize = 0; + do { + + LastImage = TRUE; + + ZeroMem (&EfiRomHeader, sizeof(EfiRomHeader)); + IoDev->Mem.Read ( + IoDev, + EfiPciWidthUint8, + RomBar + RomBarSize, + sizeof(EfiRomHeader), + &EfiRomHeader + ); + + Pcir.ImageLength = 0; + + if (EfiRomHeader.Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE && + EfiRomHeader.PcirOffset != 0 && + (EfiRomHeader.PcirOffset & 3) == 0 && + RomBarSize + EfiRomHeader.PcirOffset + sizeof (PCI_DATA_STRUCTURE) <= MaxRomSize) { + ZeroMem (&Pcir, sizeof(Pcir)); + IoDev->Mem.Read ( + IoDev, + EfiPciWidthUint8, + RomBar + RomBarSize + EfiRomHeader.PcirOffset, + sizeof(Pcir), + &Pcir + ); + + if (Pcir.Signature != PCI_DATA_STRUCTURE_SIGNATURE) { + break; + } + if (RomBarSize + Pcir.ImageLength * 512 > MaxRomSize) { + break; + } + if ((Pcir.Indicator & 0x80) == 0x00) { + LastImage = FALSE; + } + + RomBarSize += Pcir.ImageLength * 512; + } + } while (!LastImage && RomBarSize < MaxRomSize && Pcir.ImageLength !=0); + + if (RomBarSize > 0) { + + // + // Allocate a memory buffer for the Option ROM contents. + // + Status = gBS->AllocatePages( + AllocateAnyPages, + EfiBootServicesData, + EFI_SIZE_TO_PAGES(RomBarSize), + &RomBuffer + ); + + if (!EFI_ERROR (Status)) { + + // + // Copy the contents of the Option ROM to the memory buffer + // + IoDev->Mem.Read (IoDev, EfiPciWidthUint32, RomBar, RomBarSize / sizeof(UINT32), (VOID *)(UINTN)RomBuffer); + + Status = gBS->AllocatePool( + EfiBootServicesData, + ((UINT32)mPciOptionRomTable.PciOptionRomCount + 1) * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR), + (VOID*)&TempPciOptionRomDescriptors + ); + if (mPciOptionRomTable.PciOptionRomCount > 0) { + CopyMem( + TempPciOptionRomDescriptors, + mPciOptionRomTable.PciOptionRomDescriptors, + (UINT32)mPciOptionRomTable.PciOptionRomCount * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR) + ); + + gBS->FreePool(mPciOptionRomTable.PciOptionRomDescriptors); + } + + mPciOptionRomTable.PciOptionRomDescriptors = TempPciOptionRomDescriptors; + + TempPciOptionRomDescriptors = &(mPciOptionRomTable.PciOptionRomDescriptors[(UINT32)mPciOptionRomTable.PciOptionRomCount]); + + TempPciOptionRomDescriptors->RomAddress = RomBuffer; + TempPciOptionRomDescriptors->MemoryType = EfiBootServicesData; + TempPciOptionRomDescriptors->RomLength = RomBarSize; + TempPciOptionRomDescriptors->Seg = (UINT32)IoDev->SegmentNumber; + TempPciOptionRomDescriptors->Bus = (UINT8)Bus; + TempPciOptionRomDescriptors->Dev = (UINT8)Device; + TempPciOptionRomDescriptors->Func = (UINT8)Func; + TempPciOptionRomDescriptors->ExecutedLegacyBiosImage = TRUE; + TempPciOptionRomDescriptors->DontLoadEfiRom = FALSE; + + mPciOptionRomTable.PciOptionRomCount++; + } + } + + // + // Disable the Memory decode for the PCI-PCI Bridge + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + Register &= (~0x02); + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + } + } + } + + // + // Restore the PCI Configuration Header + // + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader); +} + +VOID +SaveCommandRegister ( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + UINT16 Bus, + UINT16 Device, + UINT16 Func, + IN VOID *VoidContext + ) + +{ + PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context; + UINT64 Address; + UINTN Index; + UINT16 Command; + + Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext; + + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4); + + Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func; + + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]); + + // + // Clear the memory enable bit + // + Command = (UINT16) (Context->CommandRegisterBuffer[Index] & (~0x02)); + + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Command); +} + +VOID +RestoreCommandRegister ( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + UINT16 Bus, + UINT16 Device, + UINT16 Func, + IN VOID *VoidContext + ) + +{ + PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context; + UINT64 Address; + UINTN Index; + + Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext; + + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4); + + Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func; + + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]); +} + +EFI_STATUS +ScanPciRootBridgeForRoms( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev + ) + +{ + EFI_STATUS Status; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; + UINT16 MinBus; + UINT16 MaxBus; + UINT64 RootWindowBase; + UINT64 RootWindowLimit; + PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT Context; + + if (mPciOptionRomTableInstalled == FALSE) { + gBS->InstallConfigurationTable(&gEfiPciOptionRomTableGuid, &mPciOptionRomTable); + mPciOptionRomTableInstalled = TRUE; + } + + Status = IoDev->Configuration(IoDev, (VOID **)&Descriptors); + if (EFI_ERROR (Status) || Descriptors == NULL) { + return EFI_NOT_FOUND; + } + + MinBus = 0xffff; + MaxBus = 0xffff; + RootWindowBase = 0; + RootWindowLimit = 0; + while (Descriptors->Desc != ACPI_END_TAG_DESCRIPTOR) { + // + // Find bus range + // + if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) { + MinBus = (UINT16)Descriptors->AddrRangeMin; + MaxBus = (UINT16)Descriptors->AddrRangeMax; + } + // + // Find memory descriptors that are not prefetchable + // + if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM && Descriptors->SpecificFlag == 0) { + // + // Find Memory Descriptors that are less than 4GB, so the PPB Memory Window can be used for downstream devices + // + if (Descriptors->AddrRangeMax < 0x100000000ULL) { + // + // Find the largest Non-Prefetchable Memory Descriptor that is less than 4GB + // + if ((Descriptors->AddrRangeMax - Descriptors->AddrRangeMin) > (RootWindowLimit - RootWindowBase)) { + RootWindowBase = Descriptors->AddrRangeMin; + RootWindowLimit = Descriptors->AddrRangeMax; + } + } + } + Descriptors ++; + } + + // + // Make sure a bus range was found + // + if (MinBus == 0xffff || MaxBus == 0xffff) { + return EFI_NOT_FOUND; + } + + // + // Make sure a non-prefetchable memory region was found + // + if (RootWindowBase == 0 && RootWindowLimit == 0) { + return EFI_NOT_FOUND; + } + + // + // Round the Base and Limit values to 1 MB boudaries + // + RootWindowBase = ((RootWindowBase - 1) & 0xfff00000) + 0x00100000; + RootWindowLimit = ((RootWindowLimit + 1) & 0xfff00000) - 1; + + // + // Make sure that the size of the rounded window is greater than zero + // + if (RootWindowLimit <= RootWindowBase) { + return EFI_NOT_FOUND; + } + + // + // Allocate buffer to save the Command register from all the PCI devices + // + Context.CommandRegisterBuffer = NULL; + Status = gBS->AllocatePool( + EfiBootServicesData, + sizeof(UINT16) * (MaxBus - MinBus + 1) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1), + (VOID **)&Context.CommandRegisterBuffer + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Context.PpbMemoryWindow = (((UINT32)RootWindowBase) >> 16) | ((UINT32)RootWindowLimit & 0xffff0000); + + // + // Save the Command register from all the PCI devices, and disable the I/O, Mem, and BusMaster bits + // + ScanPciBus( + IoDev, + MinBus, MaxBus, + 0, PCI_MAX_DEVICE, + 0, PCI_MAX_FUNC, + SaveCommandRegister, &Context + ); + + // + // Recursively scan all the busses for PCI Option ROMs + // + ScanPciBus( + IoDev, + MinBus, MinBus, + 0, PCI_MAX_DEVICE, + 0, PCI_MAX_FUNC, + CheckForRom, &Context + ); + + // + // Restore the Command register in all the PCI devices + // + ScanPciBus( + IoDev, + MinBus, MaxBus, + 0, PCI_MAX_DEVICE, + 0, PCI_MAX_FUNC, + RestoreCommandRegister, &Context + ); + + // + // Free the buffer used to save all the Command register values + // + gBS->FreePool(Context.CommandRegisterBuffer); + + return EFI_SUCCESS; +} diff --git a/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/Ipf/PcatIo.c b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/Ipf/PcatIo.c new file mode 100644 index 0000000000..f4a7ffabf8 --- /dev/null +++ b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/Ipf/PcatIo.c @@ -0,0 +1,459 @@ +/*++ + +Copyright (c) 2005 - 2012, 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: + PcatPciRootBridgeIo.c + +Abstract: + + EFI PC AT PCI Root Bridge Io Protocol + +Revision History + +--*/ + +#include "PcatPciRootBridge.h" +#include <IndustryStandard/Pci.h> +#include "SalProc.h" + +#include EFI_GUID_DEFINITION (SalSystemTable) + +// +// Might be good to put this in an include file, but people may start +// using it! They should always access the EFI abstraction that is +// contained in this file. Just a little information hiding. +// +#define PORT_TO_MEM(_Port) ( ((_Port) & 0xffffffffffff0000) | (((_Port) & 0xfffc) << 10) | ((_Port) & 0x0fff) ) + +// +// Macro's with casts make this much easier to use and read. +// +#define PORT_TO_MEM8(_Port) (*(UINT8 *)(PORT_TO_MEM(_Port))) +#define PORT_TO_MEM16(_Port) (*(UINT16 *)(PORT_TO_MEM(_Port))) +#define PORT_TO_MEM32(_Port) (*(UINT32 *)(PORT_TO_MEM(_Port))) + +#define EFI_PCI_ADDRESS_IA64(_seg, _bus,_dev,_func,_reg) \ + ( (UINT64) ( (((UINTN)_seg) << 24) + (((UINTN)_bus) << 16) + (((UINTN)_dev) << 11) + (((UINTN)_func) << 8) + ((UINTN)_reg)) ) + +// +// Local variables for performing SAL Proc calls +// +PLABEL mSalProcPlabel; +CALL_SAL_PROC mGlobalSalProc; + +EFI_STATUS +PcatRootBridgeIoIoRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + UINTN InStride; + UINTN OutStride; + UINTN AlignMask; + UINTN Address; + PTR Buffer; + UINT16 Data16; + UINT32 Data32; + + + if ( UserBuffer == NULL ) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + Address = (UINTN) UserAddress; + Buffer.buf = (UINT8 *)UserBuffer; + + if ( Address < PrivateData->IoBase || Address > PrivateData->IoLimit ) { + return EFI_INVALID_PARAMETER; + } + + if ((UINT32)Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + if ((Width & 0x03) == EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + AlignMask = (1 << (Width & 0x03)) - 1; + if ( Address & AlignMask ) { + return EFI_INVALID_PARAMETER; + } + + InStride = 1 << (Width & 0x03); + OutStride = InStride; + if (Width >=EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + InStride = 0; + } + if (Width >=EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) { + OutStride = 0; + } + Width = Width & 0x03; + + Address += PrivateData->PhysicalIoBase; + + // + // Loop for each iteration and move the data + // + + switch (Width) { + case EfiPciWidthUint8: + for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) { + MEMORY_FENCE(); + *Buffer.ui8 = PORT_TO_MEM8(Address); + MEMORY_FENCE(); + } + break; + + case EfiPciWidthUint16: + for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) { + MEMORY_FENCE(); + if (Buffer.ui & 0x1) { + Data16 = PORT_TO_MEM16(Address); + *Buffer.ui8 = (UINT8)(Data16 & 0xff); + *(Buffer.ui8+1) = (UINT8)((Data16 >> 8) & 0xff); + } else { + *Buffer.ui16 = PORT_TO_MEM16(Address); + } + MEMORY_FENCE(); + } + break; + + case EfiPciWidthUint32: + for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) { + MEMORY_FENCE(); + if (Buffer.ui & 0x3) { + Data32 = PORT_TO_MEM32(Address); + *Buffer.ui8 = (UINT8)(Data32 & 0xff); + *(Buffer.ui8+1) = (UINT8)((Data32 >> 8) & 0xff); + *(Buffer.ui8+2) = (UINT8)((Data32 >> 16) & 0xff); + *(Buffer.ui8+3) = (UINT8)((Data32 >> 24) & 0xff); + } else { + *Buffer.ui32 = PORT_TO_MEM32(Address); + } + MEMORY_FENCE(); + } + break; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PcatRootBridgeIoIoWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + UINTN InStride; + UINTN OutStride; + UINTN AlignMask; + UINTN Address; + PTR Buffer; + UINT16 Data16; + UINT32 Data32; + + if ( UserBuffer == NULL ) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + Address = (UINTN) UserAddress; + Buffer.buf = (UINT8 *)UserBuffer; + + if ( Address < PrivateData->IoBase || Address > PrivateData->IoLimit ) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + if ((Width & 0x03) == EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + AlignMask = (1 << (Width & 0x03)) - 1; + if ( Address & AlignMask ) { + return EFI_INVALID_PARAMETER; + } + + InStride = 1 << (Width & 0x03); + OutStride = InStride; + if (Width >=EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + InStride = 0; + } + if (Width >=EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) { + OutStride = 0; + } + Width = Width & 0x03; + + Address += PrivateData->PhysicalIoBase; + + // + // Loop for each iteration and move the data + // + + switch (Width) { + case EfiPciWidthUint8: + for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) { + MEMORY_FENCE(); + PORT_TO_MEM8(Address) = *Buffer.ui8; + MEMORY_FENCE(); + } + break; + + case EfiPciWidthUint16: + for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) { + MEMORY_FENCE(); + if (Buffer.ui & 0x1) { + Data16 = *Buffer.ui8; + Data16 = Data16 | (*(Buffer.ui8+1) << 8); + PORT_TO_MEM16(Address) = Data16; + } else { + PORT_TO_MEM16(Address) = *Buffer.ui16; + } + MEMORY_FENCE(); + } + break; + case EfiPciWidthUint32: + for (; Count > 0; Count--, Buffer.buf += OutStride, Address += InStride) { + MEMORY_FENCE(); + if (Buffer.ui & 0x3) { + Data32 = *Buffer.ui8; + Data32 = Data32 | (*(Buffer.ui8+1) << 8); + Data32 = Data32 | (*(Buffer.ui8+2) << 16); + Data32 = Data32 | (*(Buffer.ui8+3) << 24); + PORT_TO_MEM32(Address) = Data32; + } else { + PORT_TO_MEM32(Address) = *Buffer.ui32; + } + MEMORY_FENCE(); + } + break; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PcatRootBridgeIoGetIoPortMapping ( + OUT EFI_PHYSICAL_ADDRESS *IoPortMapping, + OUT EFI_PHYSICAL_ADDRESS *MemoryPortMapping + ) +/*++ + + Get the IO Port Map from the SAL System Table. + +--*/ +{ + SAL_SYSTEM_TABLE_ASCENDING_ORDER *SalSystemTable; + SAL_ST_MEMORY_DESCRIPTOR_ENTRY *SalMemDesc; + EFI_STATUS Status; + + // + // On all Itanium architectures, bit 63 is the I/O bit for performming Memory Mapped I/O operations + // + *MemoryPortMapping = 0x8000000000000000; + + Status = EfiLibGetSystemConfigurationTable(&gEfiSalSystemTableGuid, &SalSystemTable); + if (EFI_ERROR(Status)) { + return EFI_NOT_FOUND; + } + + // + // BugBug: Add code to test checksum on the Sal System Table + // + if (SalSystemTable->Entry0.Type != 0) { + return EFI_UNSUPPORTED; + } + + mSalProcPlabel.ProcEntryPoint = SalSystemTable->Entry0.SalProcEntry; + mSalProcPlabel.GP = SalSystemTable->Entry0.GlobalDataPointer; + mGlobalSalProc = (CALL_SAL_PROC)&mSalProcPlabel.ProcEntryPoint; + + // + // The SalSystemTable pointer includes the Type 0 entry. + // The SalMemDesc is Type 1 so it comes next. + // + SalMemDesc = (SAL_ST_MEMORY_DESCRIPTOR_ENTRY *)(SalSystemTable + 1); + while (SalMemDesc->Type == SAL_ST_MEMORY_DESCRIPTOR) { + if (SalMemDesc->MemoryType == SAL_IO_PORT_MAPPING) { + *IoPortMapping = SalMemDesc->PhysicalMemoryAddress; + *IoPortMapping |= 0x8000000000000000; + return EFI_SUCCESS; + } + SalMemDesc++; + } + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PcatRootBridgeIoPciRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN BOOLEAN Write, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT UINT8 *UserBuffer + ) +{ + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + UINTN AlignMask; + UINTN InStride; + UINTN OutStride; + UINT64 Address; + DEFIO_PCI_ADDR *Defio; + PTR Buffer; + UINT32 Data32; + UINT16 Data16; + rArg Return; + + if (Width < 0 || Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + if ((Width & 0x03) == EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + AlignMask = (1 << (Width & 0x03)) - 1; + if ( UserAddress & AlignMask ) { + return EFI_INVALID_PARAMETER; + } + + InStride = 1 << (Width & 0x03); + OutStride = InStride; + if (Width >=EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + InStride = 0; + } + if (Width >=EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) { + OutStride = 0; + } + Width = Width & 0x03; + + Defio = (DEFIO_PCI_ADDR *)&UserAddress; + + if ((Defio->Function > PCI_MAX_FUNC) || (Defio->Device > PCI_MAX_DEVICE)) { + return EFI_UNSUPPORTED; + } + + Buffer.buf = (UINT8 *)UserBuffer; + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + Address = EFI_PCI_ADDRESS_IA64( + This->SegmentNumber, + Defio->Bus, + Defio->Device, + Defio->Function, + Defio->Register + ); + + // + // PCI Config access are all 32-bit alligned, but by accessing the + // CONFIG_DATA_REGISTER (0xcfc) with different widths more cycle types + // are possible on PCI. + // + // SalProc takes care of reading the proper register depending on stride + // + + EfiAcquireLock(&PrivateData->PciLock); + + while (Count) { + + if(Write) { + + if (Buffer.ui & 0x3) { + Data32 = (*(Buffer.ui8+0) << 0); + Data32 |= (*(Buffer.ui8+1) << 8); + Data32 |= (*(Buffer.ui8+2) << 16); + Data32 |= (*(Buffer.ui8+3) << 24); + } else { + Data32 = *Buffer.ui32; + } + + Return.p0 = -3; + Return = mGlobalSalProc((UINT64) SAL_PCI_CONFIG_WRITE, + Address, 1 << Width, Data32, 0, 0, 0, 0); + + if(Return.p0) { + EfiReleaseLock(&PrivateData->PciLock); + return EFI_UNSUPPORTED; + } + + } else { + + Return.p0 = -3; + Return = mGlobalSalProc((UINT64) SAL_PCI_CONFIG_READ, + Address, 1 << Width, 0, 0, 0, 0, 0); + + if(Return.p0) { + EfiReleaseLock(&PrivateData->PciLock); + return EFI_UNSUPPORTED; + } + + switch (Width) { + case EfiPciWidthUint8: + *Buffer.ui8 = (UINT8)Return.p1; + break; + case EfiPciWidthUint16: + if (Buffer.ui & 0x1) { + Data16 = (UINT16)Return.p1; + *(Buffer.ui8 + 0) = Data16 & 0xff; + *(Buffer.ui8 + 1) = (Data16 >> 8) & 0xff; + } else { + *Buffer.ui16 = (UINT16)Return.p1; + } + break; + case EfiPciWidthUint32: + if (Buffer.ui & 0x3) { + Data32 = (UINT32)Return.p1; + *(Buffer.ui8 + 0) = (UINT8)(Data32 & 0xff); + *(Buffer.ui8 + 1) = (UINT8)((Data32 >> 8) & 0xff); + *(Buffer.ui8 + 2) = (UINT8)((Data32 >> 16) & 0xff); + *(Buffer.ui8 + 3) = (UINT8)((Data32 >> 24) & 0xff); + } else { + *Buffer.ui32 = (UINT32)Return.p1; + } + break; + } + } + + Address += InStride; + Buffer.buf += OutStride; + Count -= 1; + } + + EfiReleaseLock(&PrivateData->PciLock); + + return EFI_SUCCESS; +} + +EFI_STATUS +ScanPciRootBridgeForRoms( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev + ) + +{ + return EFI_UNSUPPORTED; +} diff --git a/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridge.c b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridge.c new file mode 100644 index 0000000000..e76db54e57 --- /dev/null +++ b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridge.c @@ -0,0 +1,1009 @@ +/*++ + +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; +} + diff --git a/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridge.h b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridge.h new file mode 100644 index 0000000000..6cb86c7efa --- /dev/null +++ b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridge.h @@ -0,0 +1,244 @@ +/*++ + +Copyright (c) 2005 - 2006, 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.h + +Abstract: + + The driver for the host to pci bridge (root bridge). + +--*/ + +#ifndef _PCAT_PCI_ROOT_BRIDGE_H_ +#define _PCAT_PCI_ROOT_BRIDGE_H_ + +#include <PiDxe.h> +#include <Protocol/PciRootBridgeIo.h> +#include <Protocol/DeviceIo.h> +#include <Protocol/CpuIo2.h> + +#include <Library/UefiLib.h> +#include <Library/BaseLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DevicePathLib.h> +#include <Library/HobLib.h> + +#include <Guid/PciOptionRomTable.h> +#include <Guid/HobList.h> +#include <Guid/PciExpressBaseAddress.h> + +#include <IndustryStandard/Acpi.h> +#include <IndustryStandard/Pci.h> + +#define PCI_MAX_SEGMENT 0 +// +// Driver Instance Data Prototypes +// +#define PCAT_PCI_ROOT_BRIDGE_SIGNATURE SIGNATURE_32('p', 'c', 'r', 'b') + +typedef struct { + UINT32 Signature; + EFI_HANDLE Handle; + + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL Io; + EFI_CPU_IO2_PROTOCOL *CpuIo; + + UINT32 RootBridgeNumber; + UINT32 PrimaryBus; + UINT32 SubordinateBus; + + UINT64 MemBase; // Offsets host to bus memory addr. + UINT64 MemLimit; // Max allowable memory access + + UINT64 IoBase; // Offsets host to bus io addr. + UINT64 IoLimit; // Max allowable io access + + UINT64 PciAddress; + UINT64 PciData; + + UINT64 PhysicalMemoryBase; + UINT64 PhysicalIoBase; + + EFI_LOCK PciLock; + + UINT64 Attributes; + + UINT64 Mem32Base; + UINT64 Mem32Limit; + UINT64 Pmem32Base; + UINT64 Pmem32Limit; + UINT64 Mem64Base; + UINT64 Mem64Limit; + UINT64 Pmem64Base; + UINT64 Pmem64Limit; + + UINT64 PciExpressBaseAddress; + + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration; + + LIST_ENTRY MapInfo; +} PCAT_PCI_ROOT_BRIDGE_INSTANCE; + +// +// Driver Instance Data Macros +// +#define DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(a) \ + CR(a, PCAT_PCI_ROOT_BRIDGE_INSTANCE, Io, PCAT_PCI_ROOT_BRIDGE_SIGNATURE) + +// +// Private data types +// +typedef union { + UINT8 volatile *buf; + UINT8 volatile *ui8; + UINT16 volatile *ui16; + UINT32 volatile *ui32; + UINT64 volatile *ui64; + UINTN volatile ui; +} PTR; + +typedef struct { + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation; + UINTN NumberOfBytes; + UINTN NumberOfPages; + EFI_PHYSICAL_ADDRESS HostAddress; + EFI_PHYSICAL_ADDRESS MappedHostAddress; +} MAP_INFO; + +typedef struct { + LIST_ENTRY Link; + MAP_INFO * Map; +} MAP_INFO_INSTANCE; + +typedef +VOID +(*EFI_PCI_BUS_SCAN_CALLBACK) ( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + UINT16 Bus, + UINT16 Device, + UINT16 Func, + IN VOID *Context + ); + +typedef struct { + UINT16 *CommandRegisterBuffer; + UINT32 PpbMemoryWindow; +} PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT; + +typedef struct { + UINT8 Register; + UINT8 Function; + UINT8 Device; + UINT8 Bus; + UINT8 Reserved[4]; +} DEFIO_PCI_ADDR; + +// +// Driver Protocol Constructor Prototypes +// +EFI_STATUS +ConstructConfiguration( + IN OUT PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData + ); + +EFI_STATUS +PcatPciRootBridgeParseBars ( + IN PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData, + IN UINT16 Command, + IN UINTN Bus, + IN UINTN Device, + IN UINTN Function + ); + +EFI_STATUS +ScanPciRootBridgeForRoms( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev + ); + +EFI_STATUS +PcatRootBridgeDevicePathConstructor ( + IN EFI_DEVICE_PATH_PROTOCOL **Protocol, + IN UINTN RootBridgeNumber, + IN BOOLEAN IsPciExpress + ); + +EFI_STATUS +PcatRootBridgeIoConstructor ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *Protocol, + IN UINTN SegmentNumber + ); + +EFI_STATUS +PcatRootBridgeIoGetIoPortMapping ( + OUT EFI_PHYSICAL_ADDRESS *IoPortMapping, + OUT EFI_PHYSICAL_ADDRESS *MemoryPortMapping + ); + +EFI_STATUS +PcatRootBridgeIoPciRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN BOOLEAN Write, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ); + +UINT64 +GetPciExpressBaseAddressForRootBridge ( + IN UINTN HostBridgeNumber, + IN UINTN RootBridgeNumber + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoIoRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoIoWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ); + +// +// Driver entry point prototype +// +EFI_STATUS +EFIAPI +InitializePcatPciRootBridge ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +extern EFI_CPU_IO2_PROTOCOL *gCpuIo; + +#endif diff --git a/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridgeDevicePath.c b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridgeDevicePath.c new file mode 100644 index 0000000000..dafa7456e6 --- /dev/null +++ b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridgeDevicePath.c @@ -0,0 +1,93 @@ +/*++ + +Copyright (c) 2005 - 2006, 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: + PcatPciRootBridgeDevicePath.c + +Abstract: + + EFI PCAT PCI Root Bridge Device Path Protocol + +Revision History + +--*/ + +#include "PcatPciRootBridge.h" + +// +// Static device path declarations for this driver. +// + +typedef struct { + ACPI_HID_DEVICE_PATH AcpiDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH; + +EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mEfiPciRootBridgeDevicePath = { + { + { + ACPI_DEVICE_PATH, + ACPI_DP, + { + (UINT8) (sizeof(ACPI_HID_DEVICE_PATH)), + (UINT8) ((sizeof(ACPI_HID_DEVICE_PATH)) >> 8), + } + }, + EISA_PNP_ID(0x0A03), + 0 + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } +}; + +EFI_STATUS +PcatRootBridgeDevicePathConstructor ( + IN EFI_DEVICE_PATH_PROTOCOL **Protocol, + IN UINTN RootBridgeNumber, + IN BOOLEAN IsPciExpress + ) +/*++ + +Routine Description: + + Construct the device path protocol + +Arguments: + + Protocol - protocol to initialize + +Returns: + + None + +--*/ +{ + ACPI_HID_DEVICE_PATH *AcpiDevicePath; + + *Protocol = DuplicateDevicePath((EFI_DEVICE_PATH_PROTOCOL *)(&mEfiPciRootBridgeDevicePath)); + + AcpiDevicePath = (ACPI_HID_DEVICE_PATH *)(*Protocol); + + AcpiDevicePath->UID = (UINT32)RootBridgeNumber; + + if (IsPciExpress) { + AcpiDevicePath->HID = EISA_PNP_ID(0x0A08); + } + + return EFI_SUCCESS; +} + diff --git a/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridgeIo.c b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridgeIo.c new file mode 100644 index 0000000000..a3ee4782e5 --- /dev/null +++ b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/PcatPciRootBridgeIo.c @@ -0,0 +1,1036 @@ +/*++ + +Copyright (c) 2005 - 2012, 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: + PcatPciRootBridgeIo.c + +Abstract: + + EFI PC AT PCI Root Bridge Io Protocol + +Revision History + +--*/ + +#include "PcatPciRootBridge.h" + +// +// Protocol Member Function Prototypes +// +EFI_STATUS +EFIAPI +PcatRootBridgeIoPollMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoPollIo ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoMemRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoMemWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoCopyMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 DestAddress, + IN UINT64 SrcAddress, + IN UINTN Count + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoPciRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoPciWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoMap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoUnmap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN VOID *Mapping + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoAllocateBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoFreeBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINTN Pages, + OUT VOID *HostAddress + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoFlush ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoGetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT UINT64 *Supported, + OUT UINT64 *Attributes + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoSetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN OUT UINT64 *ResourceBase, + IN OUT UINT64 *ResourceLength + ); + +EFI_STATUS +EFIAPI +PcatRootBridgeIoConfiguration ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT VOID **Resources + ); + +// +// Private Function Prototypes +// +EFI_STATUS +EFIAPI +PcatRootBridgeIoMemRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINTN Count, + IN BOOLEAN InStrideFlag, + IN PTR In, + IN BOOLEAN OutStrideFlag, + OUT PTR Out + ); + +EFI_STATUS +PcatRootBridgeIoConstructor ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *Protocol, + IN UINTN SegmentNumber + ) +/*++ + +Routine Description: + + Contruct the Pci Root Bridge Io protocol + +Arguments: + + Protocol - protocol to initialize + +Returns: + + None + +--*/ +{ + Protocol->ParentHandle = NULL; + + Protocol->PollMem = PcatRootBridgeIoPollMem; + Protocol->PollIo = PcatRootBridgeIoPollIo; + + Protocol->Mem.Read = PcatRootBridgeIoMemRead; + Protocol->Mem.Write = PcatRootBridgeIoMemWrite; + + Protocol->Io.Read = PcatRootBridgeIoIoRead; + Protocol->Io.Write = PcatRootBridgeIoIoWrite; + + Protocol->CopyMem = PcatRootBridgeIoCopyMem; + + Protocol->Pci.Read = PcatRootBridgeIoPciRead; + Protocol->Pci.Write = PcatRootBridgeIoPciWrite; + + Protocol->Map = PcatRootBridgeIoMap; + Protocol->Unmap = PcatRootBridgeIoUnmap; + + Protocol->AllocateBuffer = PcatRootBridgeIoAllocateBuffer; + Protocol->FreeBuffer = PcatRootBridgeIoFreeBuffer; + + Protocol->Flush = PcatRootBridgeIoFlush; + + Protocol->GetAttributes = PcatRootBridgeIoGetAttributes; + Protocol->SetAttributes = PcatRootBridgeIoSetAttributes; + + Protocol->Configuration = PcatRootBridgeIoConfiguration; + + Protocol->SegmentNumber = (UINT32)SegmentNumber; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoPollMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ) +{ + EFI_STATUS Status; + UINT64 NumberOfTicks; + UINT32 Remainder; + + if (Result == NULL) { + return EFI_INVALID_PARAMETER; + } + + + if ((UINT32)Width > EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + // + // No matter what, always do a single poll. + // + Status = This->Mem.Read (This, Width, Address, 1, Result); + if ( EFI_ERROR(Status) ) { + return Status; + } + if ( (*Result & Mask) == Value ) { + return EFI_SUCCESS; + } + + if (Delay == 0) { + return EFI_SUCCESS; + } else { + + NumberOfTicks = DivU64x32Remainder (Delay, 100, &Remainder); + if ( Remainder !=0 ) { + NumberOfTicks += 1; + } + NumberOfTicks += 1; + + while ( NumberOfTicks ) { + + gBS->Stall (10); + + Status = This->Mem.Read (This, Width, Address, 1, Result); + if ( EFI_ERROR(Status) ) { + return Status; + } + + if ( (*Result & Mask) == Value ) { + return EFI_SUCCESS; + } + + NumberOfTicks -= 1; + } + } + return EFI_TIMEOUT; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoPollIo ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ) +{ + EFI_STATUS Status; + UINT64 NumberOfTicks; + UINT32 Remainder; + + if (Result == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((UINT32)Width > EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + // + // No matter what, always do a single poll. + // + Status = This->Io.Read (This, Width, Address, 1, Result); + if ( EFI_ERROR(Status) ) { + return Status; + } + if ( (*Result & Mask) == Value ) { + return EFI_SUCCESS; + } + + if (Delay == 0) { + return EFI_SUCCESS; + } else { + + NumberOfTicks = DivU64x32Remainder (Delay, 100, &Remainder); + if ( Remainder !=0 ) { + NumberOfTicks += 1; + } + NumberOfTicks += 1; + + while ( NumberOfTicks ) { + + gBS->Stall(10); + + Status = This->Io.Read (This, Width, Address, 1, Result); + if ( EFI_ERROR(Status) ) { + return Status; + } + + if ( (*Result & Mask) == Value ) { + return EFI_SUCCESS; + } + + NumberOfTicks -= 1; + } + } + return EFI_TIMEOUT; +} + +BOOLEAN +PcatRootBridgeMemAddressValid ( + IN PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData, + IN UINT64 Address + ) +{ + if ((Address >= PrivateData->PciExpressBaseAddress) && (Address < PrivateData->PciExpressBaseAddress + 0x10000000)) { + return TRUE; + } + if ((Address >= PrivateData->MemBase) && (Address < PrivateData->MemLimit)) { + return TRUE; + } + + return FALSE; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoMemRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + UINTN AlignMask; + PTR In; + PTR Out; + + if ( Buffer == NULL ) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + if (!PcatRootBridgeMemAddressValid (PrivateData, Address)) { + return EFI_INVALID_PARAMETER; + } + + AlignMask = (1 << (Width & 0x03)) - 1; + if (Address & AlignMask) { + return EFI_INVALID_PARAMETER; + } + + Address += PrivateData->PhysicalMemoryBase; + + In.buf = Buffer; + Out.buf = (VOID *)(UINTN) Address; + if ((UINT32)Width <= EfiPciWidthUint64) { + return PcatRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out); + } + if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + return PcatRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out); + } + if (Width >= EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) { + return PcatRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out); + } + + return EFI_INVALID_PARAMETER; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoMemWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + UINTN AlignMask; + PTR In; + PTR Out; + + if ( Buffer == NULL ) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + if (!PcatRootBridgeMemAddressValid (PrivateData, Address)) { + return EFI_INVALID_PARAMETER; + } + + AlignMask = (1 << (Width & 0x03)) - 1; + if (Address & AlignMask) { + return EFI_INVALID_PARAMETER; + } + + Address += PrivateData->PhysicalMemoryBase; + + In.buf = (VOID *)(UINTN) Address; + Out.buf = Buffer; + if ((UINT32)Width <= EfiPciWidthUint64) { + return PcatRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out); + } + if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + return PcatRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out); + } + if (Width >= EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) { + return PcatRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out); + } + + return EFI_INVALID_PARAMETER; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoCopyMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 DestAddress, + IN UINT64 SrcAddress, + IN UINTN Count + ) + +{ + EFI_STATUS Status; + BOOLEAN Direction; + UINTN Stride; + UINTN Index; + UINT64 Result; + + if ((UINT32)Width > EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + if (DestAddress == SrcAddress) { + return EFI_SUCCESS; + } + + Stride = (UINTN)1 << Width; + + Direction = TRUE; + if ((DestAddress > SrcAddress) && (DestAddress < (SrcAddress + Count * Stride))) { + Direction = FALSE; + SrcAddress = SrcAddress + (Count-1) * Stride; + DestAddress = DestAddress + (Count-1) * Stride; + } + + for (Index = 0;Index < Count;Index++) { + Status = PcatRootBridgeIoMemRead ( + This, + Width, + SrcAddress, + 1, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + Status = PcatRootBridgeIoMemWrite ( + This, + Width, + DestAddress, + 1, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + if (Direction) { + SrcAddress += Stride; + DestAddress += Stride; + } else { + SrcAddress -= Stride; + DestAddress -= Stride; + } + } + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoPciRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + return PcatRootBridgeIoPciRW (This, FALSE, Width, Address, Count, Buffer); +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoPciWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + return PcatRootBridgeIoPciRW (This, TRUE, Width, Address, Count, Buffer); +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoMap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) + +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS PhysicalAddress; + MAP_INFO *MapInfo; + MAP_INFO_INSTANCE *MapInstance; + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + + if ( HostAddress == NULL || NumberOfBytes == NULL || + DeviceAddress == NULL || Mapping == NULL ) { + + return EFI_INVALID_PARAMETER; + } + + // + // Perform a fence operation to make sure all memory operations are flushed + // + MemoryFence(); + + // + // Initialize the return values to their defaults + // + *Mapping = NULL; + + // + // Make sure that Operation is valid + // + if ((UINT32)Operation >= EfiPciOperationMaximum) { + return EFI_INVALID_PARAMETER; + } + + // + // Most PCAT like chipsets can not handle performing DMA above 4GB. + // If any part of the DMA transfer being mapped is above 4GB, then + // map the DMA transfer to a buffer below 4GB. + // + PhysicalAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress; + if ((PhysicalAddress + *NumberOfBytes) > 0x100000000ULL) { + + // + // Common Buffer operations can not be remapped. If the common buffer + // if above 4GB, then it is not possible to generate a mapping, so return + // an error. + // + if (Operation == EfiPciOperationBusMasterCommonBuffer || Operation == EfiPciOperationBusMasterCommonBuffer64) { + return EFI_UNSUPPORTED; + } + + // + // Allocate a MAP_INFO structure to remember the mapping when Unmap() is + // called later. + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof(MAP_INFO), + (VOID **)&MapInfo + ); + if (EFI_ERROR (Status)) { + *NumberOfBytes = 0; + return Status; + } + + // + // Return a pointer to the MAP_INFO structure in Mapping + // + *Mapping = MapInfo; + + // + // Initialize the MAP_INFO structure + // + MapInfo->Operation = Operation; + MapInfo->NumberOfBytes = *NumberOfBytes; + MapInfo->NumberOfPages = EFI_SIZE_TO_PAGES(*NumberOfBytes); + MapInfo->HostAddress = PhysicalAddress; + MapInfo->MappedHostAddress = 0x00000000ffffffff; + + // + // Allocate a buffer below 4GB to map the transfer to. + // + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiBootServicesData, + MapInfo->NumberOfPages, + &MapInfo->MappedHostAddress + ); + if (EFI_ERROR(Status)) { + gBS->FreePool (MapInfo); + *NumberOfBytes = 0; + return Status; + } + + // + // If this is a read operation from the Bus Master's point of view, + // then copy the contents of the real buffer into the mapped buffer + // so the Bus Master can read the contents of the real buffer. + // + if (Operation == EfiPciOperationBusMasterRead || Operation == EfiPciOperationBusMasterRead64) { + CopyMem ( + (VOID *)(UINTN)MapInfo->MappedHostAddress, + (VOID *)(UINTN)MapInfo->HostAddress, + MapInfo->NumberOfBytes + ); + } + + + Status =gBS->AllocatePool ( + EfiBootServicesData, + sizeof(MAP_INFO_INSTANCE), + (VOID **)&MapInstance + ); + if (EFI_ERROR(Status)) { + gBS->FreePages (MapInfo->MappedHostAddress,MapInfo->NumberOfPages); + gBS->FreePool (MapInfo); + *NumberOfBytes = 0; + return Status; + } + + MapInstance->Map=MapInfo; + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + InsertTailList(&PrivateData->MapInfo,&MapInstance->Link); + + // + // The DeviceAddress is the address of the maped buffer below 4GB + // + *DeviceAddress = MapInfo->MappedHostAddress; + } else { + // + // The transfer is below 4GB, so the DeviceAddress is simply the HostAddress + // + *DeviceAddress = PhysicalAddress; + } + + // + // Perform a fence operation to make sure all memory operations are flushed + // + MemoryFence(); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoUnmap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN VOID *Mapping + ) + +{ + MAP_INFO *MapInfo; + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + LIST_ENTRY *Link; + + // + // Perform a fence operation to make sure all memory operations are flushed + // + MemoryFence(); + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + // + // See if the Map() operation associated with this Unmap() required a mapping buffer. + // If a mapping buffer was not required, then this function simply returns EFI_SUCCESS. + // + if (Mapping != NULL) { + // + // Get the MAP_INFO structure from Mapping + // + MapInfo = (MAP_INFO *)Mapping; + + for (Link = PrivateData->MapInfo.ForwardLink; Link != &PrivateData->MapInfo; Link = Link->ForwardLink) { + if (((MAP_INFO_INSTANCE*)Link)->Map == MapInfo) + break; + } + + if (Link == &PrivateData->MapInfo) { + return EFI_INVALID_PARAMETER; + } + + RemoveEntryList(Link); + ((MAP_INFO_INSTANCE*)Link)->Map = NULL; + gBS->FreePool((MAP_INFO_INSTANCE*)Link); + + // + // If this is a write operation from the Bus Master's point of view, + // then copy the contents of the mapped buffer into the real buffer + // so the processor can read the contents of the real buffer. + // + if (MapInfo->Operation == EfiPciOperationBusMasterWrite || MapInfo->Operation == EfiPciOperationBusMasterWrite64) { + CopyMem ( + (VOID *)(UINTN)MapInfo->HostAddress, + (VOID *)(UINTN)MapInfo->MappedHostAddress, + MapInfo->NumberOfBytes + ); + } + + // + // Free the mapped buffer and the MAP_INFO structure. + // + gBS->FreePages (MapInfo->MappedHostAddress, MapInfo->NumberOfPages); + gBS->FreePool (Mapping); + } + + // + // Perform a fence operation to make sure all memory operations are flushed + // + MemoryFence(); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoAllocateBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS PhysicalAddress; + + // + // Validate Attributes + // + if (Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) { + return EFI_UNSUPPORTED; + } + + // + // Check for invalid inputs + // + if (HostAddress == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData + // + if (MemoryType != EfiBootServicesData && MemoryType != EfiRuntimeServicesData) { + return EFI_INVALID_PARAMETER; + } + + // + // Limit allocations to memory below 4GB + // + PhysicalAddress = (EFI_PHYSICAL_ADDRESS)(0xffffffff); + + Status = gBS->AllocatePages (AllocateMaxAddress, MemoryType, Pages, &PhysicalAddress); + if (EFI_ERROR (Status)) { + return Status; + } + + *HostAddress = (VOID *)(UINTN)PhysicalAddress; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoFreeBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINTN Pages, + OUT VOID *HostAddress + ) + +{ + + if( HostAddress == NULL ){ + return EFI_INVALID_PARAMETER; + } + return gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress, Pages); +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoFlush ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This + ) + +{ + // + // Perform a fence operation to make sure all memory operations are flushed + // + MemoryFence(); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoGetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT UINT64 *Supported, OPTIONAL + OUT UINT64 *Attributes + ) + +{ + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + if (Attributes == NULL && Supported == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Supported is an OPTIONAL parameter. See if it is NULL + // + if (Supported) { + // + // This is a generic driver for a PC-AT class system. It does not have any + // chipset specific knowlegde, so none of the attributes can be set or + // cleared. Any attempt to set attribute that are already set will succeed, + // and any attempt to set an attribute that is not supported will fail. + // + *Supported = PrivateData->Attributes; + } + + // + // Set Attrbutes to the attributes detected when the PCI Root Bridge was initialized + // + + if (Attributes) { + *Attributes = PrivateData->Attributes; + } + + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoSetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN OUT UINT64 *ResourceBase, + IN OUT UINT64 *ResourceLength + ) + +{ + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + // + // This is a generic driver for a PC-AT class system. It does not have any + // chipset specific knowlegde, so none of the attributes can be set or + // cleared. Any attempt to set attribute that are already set will succeed, + // and any attempt to set an attribute that is not supported will fail. + // + if (Attributes & (~PrivateData->Attributes)) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoConfiguration ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT VOID **Resources + ) + +{ + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + *Resources = PrivateData->Configuration; + + return EFI_SUCCESS; +} + +// +// Internal function +// + +EFI_STATUS +EFIAPI +PcatRootBridgeIoMemRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINTN Count, + IN BOOLEAN InStrideFlag, + IN PTR In, + IN BOOLEAN OutStrideFlag, + OUT PTR Out + ) +/*++ + +Routine Description: + + Private service to provide the memory read/write + +Arguments: + + Width of the Memory Access + Count of the number of accesses to perform + +Returns: + + Status + + EFI_SUCCESS - Successful transaction + EFI_INVALID_PARAMETER - Unsupported width and address combination + +--*/ +{ + UINTN Stride; + UINTN InStride; + UINTN OutStride; + + + Width = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (Width & 0x03); + Stride = (UINTN)1 << Width; + InStride = InStrideFlag ? Stride : 0; + OutStride = OutStrideFlag ? Stride : 0; + + // + // Loop for each iteration and move the data + // + switch (Width) { + case EfiPciWidthUint8: + for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) { + MemoryFence(); + *In.ui8 = *Out.ui8; + MemoryFence(); + } + break; + case EfiPciWidthUint16: + for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) { + MemoryFence(); + *In.ui16 = *Out.ui16; + MemoryFence(); + } + break; + case EfiPciWidthUint32: + for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) { + MemoryFence(); + *In.ui32 = *Out.ui32; + MemoryFence(); + } + break; + default: + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + diff --git a/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/PciRootBridgeNoEnumeration.inf b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/PciRootBridgeNoEnumeration.inf new file mode 100644 index 0000000000..33f49b2c22 --- /dev/null +++ b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/PciRootBridgeNoEnumeration.inf @@ -0,0 +1,69 @@ +## @file +# +# Copyright (c) 2005 - 2010, 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: +# +# Abstract: +# +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PcatPciRootBridge + FILE_GUID = 0F7EC77A-1EE1-400f-A99D-7CBD1FEB181E + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializePcatPciRootBridge + +[Packages] + MdePkg/MdePkg.dec + DuetPkg/DuetPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiLib + MemoryAllocationLib + UefiBootServicesTableLib + DebugLib + BaseMemoryLib + DevicePathLib + HobLib + +[Sources] + PcatPciRootBridge.h + PcatPciRootBridge.c + PcatPciRootBridgeDevicePath.c + PcatPciRootBridgeIo.c + DeviceIo.h + DeviceIo.c + +[Sources.ia32] + Ia32/PcatIo.c + +[Sources.x64] + X64/PcatIo.c + +[Sources.ipf] + Ipf/PcatIo.c + +[Protocols] + gEfiPciRootBridgeIoProtocolGuid + gEfiDeviceIoProtocolGuid + gEfiCpuIo2ProtocolGuid + +[Guids] + gEfiPciOptionRomTableGuid + gEfiPciExpressBaseAddressGuid + +[Depex] + gEfiCpuIo2ProtocolGuid diff --git a/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/X64/PcatIo.c b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/X64/PcatIo.c new file mode 100644 index 0000000000..a675b36828 --- /dev/null +++ b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/X64/PcatIo.c @@ -0,0 +1,738 @@ +/*++ + +Copyright (c) 2005 - 2012, 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: + PcatPciRootBridgeIo.c + +Abstract: + + EFI PC AT PCI Root Bridge Io Protocol + +Revision History + +--*/ + +#include "PcatPciRootBridge.h" + +BOOLEAN mPciOptionRomTableInstalled = FALSE; +EFI_PCI_OPTION_ROM_TABLE mPciOptionRomTable = {0, NULL}; + +EFI_STATUS +EFIAPI +PcatRootBridgeIoIoRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + return gCpuIo->Io.Read ( + gCpuIo, + (EFI_CPU_IO_PROTOCOL_WIDTH) Width, + UserAddress, + Count, + UserBuffer + ); +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoIoWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + return gCpuIo->Io.Write ( + gCpuIo, + (EFI_CPU_IO_PROTOCOL_WIDTH) Width, + UserAddress, + Count, + UserBuffer + ); + +} + +EFI_STATUS +PcatRootBridgeIoGetIoPortMapping ( + OUT EFI_PHYSICAL_ADDRESS *IoPortMapping, + OUT EFI_PHYSICAL_ADDRESS *MemoryPortMapping + ) +/*++ + + Get the IO Port Mapping. For IA-32 it is always 0. + +--*/ +{ + *IoPortMapping = 0; + *MemoryPortMapping = 0; + + return EFI_SUCCESS; +} + +EFI_STATUS +PcatRootBridgeIoPciRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN BOOLEAN Write, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + PCI_CONFIG_ACCESS_CF8 Pci; + PCI_CONFIG_ACCESS_CF8 PciAligned; + UINT32 InStride; + UINT32 OutStride; + UINTN PciData; + UINTN PciDataStride; + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress; + UINT64 PciExpressRegAddr; + BOOLEAN UsePciExpressAccess; + + if ((UINT32)Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + if ((Width & 0x03) >= EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + InStride = 1 << (Width & 0x03); + OutStride = InStride; + if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + InStride = 0; + } + + if (Width >= EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) { + OutStride = 0; + } + + UsePciExpressAccess = FALSE; + + CopyMem (&PciAddress, &UserAddress, sizeof(UINT64)); + + if (PciAddress.ExtendedRegister > 0xFF) { + // + // Check PciExpressBaseAddress + // + if ((PrivateData->PciExpressBaseAddress == 0) || + (PrivateData->PciExpressBaseAddress >= MAX_ADDRESS)) { + return EFI_UNSUPPORTED; + } else { + UsePciExpressAccess = TRUE; + } + } else { + if (PciAddress.ExtendedRegister != 0) { + Pci.Bits.Reg = PciAddress.ExtendedRegister & 0xFF; + } else { + Pci.Bits.Reg = PciAddress.Register; + } + // + // Note: We can also use PciExpress access here, if wanted. + // + } + + if (!UsePciExpressAccess) { + Pci.Bits.Func = PciAddress.Function; + Pci.Bits.Dev = PciAddress.Device; + Pci.Bits.Bus = PciAddress.Bus; + Pci.Bits.Reserved = 0; + Pci.Bits.Enable = 1; + + // + // PCI Config access are all 32-bit alligned, but by accessing the + // CONFIG_DATA_REGISTER (0xcfc) with different widths more cycle types + // are possible on PCI. + // + // To read a byte of PCI config space you load 0xcf8 and + // read 0xcfc, 0xcfd, 0xcfe, 0xcff + // + PciDataStride = Pci.Bits.Reg & 0x03; + + while (Count) { + PciAligned = Pci; + PciAligned.Bits.Reg &= 0xfc; + PciData = (UINTN)PrivateData->PciData + PciDataStride; + EfiAcquireLock(&PrivateData->PciLock); + This->Io.Write (This, EfiPciWidthUint32, PrivateData->PciAddress, 1, &PciAligned); + if (Write) { + This->Io.Write (This, Width, PciData, 1, UserBuffer); + } else { + This->Io.Read (This, Width, PciData, 1, UserBuffer); + } + EfiReleaseLock(&PrivateData->PciLock); + UserBuffer = ((UINT8 *)UserBuffer) + OutStride; + PciDataStride = (PciDataStride + InStride) % 4; + Pci.Bits.Reg += InStride; + Count -= 1; + } + } else { + // + // Access PCI-Express space by using memory mapped method. + // + PciExpressRegAddr = (PrivateData->PciExpressBaseAddress) | + (PciAddress.Bus << 20) | + (PciAddress.Device << 15) | + (PciAddress.Function << 12); + if (PciAddress.ExtendedRegister != 0) { + PciExpressRegAddr += PciAddress.ExtendedRegister; + } else { + PciExpressRegAddr += PciAddress.Register; + } + while (Count) { + if (Write) { + This->Mem.Write (This, Width, (UINTN) PciExpressRegAddr, 1, UserBuffer); + } else { + This->Mem.Read (This, Width, (UINTN) PciExpressRegAddr, 1, UserBuffer); + } + + UserBuffer = ((UINT8 *) UserBuffer) + OutStride; + PciExpressRegAddr += InStride; + Count -= 1; + } + } + + return EFI_SUCCESS; +} + +VOID +ScanPciBus( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + EFI_PCI_BUS_SCAN_CALLBACK Callback, + VOID *Context + ) + +{ + UINT16 Bus; + UINT16 Device; + UINT16 Func; + UINT64 Address; + PCI_TYPE00 PciHeader; + + // + // Loop through all busses + // + for (Bus = MinBus; Bus <= MaxBus; Bus++) { + // + // Loop 32 devices per bus + // + for (Device = MinDevice; Device <= MaxDevice; Device++) { + // + // Loop through 8 functions per device + // + for (Func = MinFunc; Func <= MaxFunc; Func++) { + + // + // Compute the EFI Address required to access the PCI Configuration Header of this PCI Device + // + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0); + + // + // Read the VendorID from this PCI Device's Confioguration Header + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &PciHeader.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 (PciHeader.Hdr.VendorId == 0xffff && Func == 0) { + break; + } + + if (PciHeader.Hdr.VendorId != 0xffff) { + + // + // Read the HeaderType to determine if this is a multi-function device + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint8, Address + 0x0e, 1, &PciHeader.Hdr.HeaderType); + + // + // Call the callback function for the device that was found + // + Callback( + IoDev, + MinBus, MaxBus, + MinDevice, MaxDevice, + MinFunc, MaxFunc, + Bus, + Device, + Func, + Context + ); + + // + // If this is not a multi-function device, we can leave the loop + // to deal with the next device. + // + if ((PciHeader.Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00 && Func == 0) { + break; + } + } + } + } + } +} + +VOID +CheckForRom ( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + UINT16 Bus, + UINT16 Device, + UINT16 Func, + IN VOID *VoidContext + ) +{ + EFI_STATUS Status; + PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context; + UINT64 Address; + PCI_TYPE00 PciHeader; + PCI_TYPE01 *PciBridgeHeader; + UINT32 Register; + UINT32 RomBar; + UINT32 RomBarSize; + EFI_PHYSICAL_ADDRESS RomBuffer; + UINT32 MaxRomSize; + EFI_PCI_EXPANSION_ROM_HEADER EfiRomHeader; + PCI_DATA_STRUCTURE Pcir; + EFI_PCI_OPTION_ROM_DESCRIPTOR *TempPciOptionRomDescriptors; + BOOLEAN LastImage; + + Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext; + + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0); + + // + // Save the contents of the PCI Configuration Header + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader); + + if (IS_PCI_BRIDGE(&PciHeader)) { + + PciBridgeHeader = (PCI_TYPE01 *)(&PciHeader); + + // + // See if the PCI-PCI Bridge has its secondary interface enabled. + // + if (PciBridgeHeader->Bridge.SubordinateBus >= PciBridgeHeader->Bridge.SecondaryBus) { + + // + // Disable the Prefetchable Memory Window + // + Register = 0x00000000; + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x26, 1, &Register); + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x2c, 1, &Register); + Register = 0xffffffff; + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x24, 1, &Register); + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x28, 1, &Register); + + // + // Program Memory Window to the PCI Root Bridge Memory Window + // + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x20, 4, &Context->PpbMemoryWindow); + + // + // Enable the Memory decode for the PCI-PCI Bridge + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + Register |= 0x02; + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + + // + // Recurse on the Secondary Bus Number + // + ScanPciBus( + IoDev, + PciBridgeHeader->Bridge.SecondaryBus, PciBridgeHeader->Bridge.SecondaryBus, + 0, PCI_MAX_DEVICE, + 0, PCI_MAX_FUNC, + CheckForRom, Context + ); + } + } else { + + // + // Check if an Option ROM Register is present and save the Option ROM Window Register + // + RomBar = 0xffffffff; + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); + IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); + + RomBarSize = (~(RomBar & 0xfffff800)) + 1; + + // + // Make sure the size of the ROM is between 0 and 16 MB + // + if (RomBarSize > 0 && RomBarSize <= 0x01000000) { + + // + // Program Option ROM Window Register to the PCI Root Bridge Window and Enable the Option ROM Window + // + RomBar = (Context->PpbMemoryWindow & 0xffff) << 16; + RomBar = ((RomBar - 1) & (~(RomBarSize - 1))) + RomBarSize; + if (RomBar < (Context->PpbMemoryWindow & 0xffff0000)) { + MaxRomSize = (Context->PpbMemoryWindow & 0xffff0000) - RomBar; + RomBar = RomBar + 1; + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); + IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); + RomBar = RomBar - 1; + + // + // Enable the Memory decode for the PCI Device + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + Register |= 0x02; + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + + // + // Follow the chain of images to determine the size of the Option ROM present + // Keep going until the last image is found by looking at the Indicator field + // or the size of an image is 0, or the size of all the images is bigger than the + // size of the window programmed into the PPB. + // + RomBarSize = 0; + do { + + LastImage = TRUE; + + ZeroMem (&EfiRomHeader, sizeof(EfiRomHeader)); + IoDev->Mem.Read ( + IoDev, + EfiPciWidthUint8, + RomBar + RomBarSize, + sizeof(EfiRomHeader), + &EfiRomHeader + ); + + Pcir.ImageLength = 0; + + if (EfiRomHeader.Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE && + EfiRomHeader.PcirOffset != 0 && + (EfiRomHeader.PcirOffset & 3) == 0 && + RomBarSize + EfiRomHeader.PcirOffset + sizeof (PCI_DATA_STRUCTURE) <= MaxRomSize) { + ZeroMem (&Pcir, sizeof(Pcir)); + IoDev->Mem.Read ( + IoDev, + EfiPciWidthUint8, + RomBar + RomBarSize + EfiRomHeader.PcirOffset, + sizeof(Pcir), + &Pcir + ); + + if (Pcir.Signature != PCI_DATA_STRUCTURE_SIGNATURE) { + break; + } + if (RomBarSize + Pcir.ImageLength * 512 > MaxRomSize) { + break; + } + if ((Pcir.Indicator & 0x80) == 0x00) { + LastImage = FALSE; + } + + RomBarSize += Pcir.ImageLength * 512; + } + } while (!LastImage && RomBarSize < MaxRomSize && Pcir.ImageLength !=0); + + if (RomBarSize > 0) { + + // + // Allocate a memory buffer for the Option ROM contents. + // + Status = gBS->AllocatePages( + AllocateAnyPages, + EfiBootServicesData, + EFI_SIZE_TO_PAGES(RomBarSize), + &RomBuffer + ); + + if (!EFI_ERROR (Status)) { + + // + // Copy the contents of the Option ROM to the memory buffer + // + IoDev->Mem.Read (IoDev, EfiPciWidthUint32, RomBar, RomBarSize / sizeof(UINT32), (VOID *)(UINTN)RomBuffer); + + Status = gBS->AllocatePool( + EfiBootServicesData, + ((UINT32)mPciOptionRomTable.PciOptionRomCount + 1) * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR), + (VOID **) &TempPciOptionRomDescriptors + ); + if (mPciOptionRomTable.PciOptionRomCount > 0) { + CopyMem( + TempPciOptionRomDescriptors, + mPciOptionRomTable.PciOptionRomDescriptors, + (UINT32)mPciOptionRomTable.PciOptionRomCount * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR) + ); + + gBS->FreePool(mPciOptionRomTable.PciOptionRomDescriptors); + } + + mPciOptionRomTable.PciOptionRomDescriptors = TempPciOptionRomDescriptors; + + TempPciOptionRomDescriptors = &(mPciOptionRomTable.PciOptionRomDescriptors[(UINT32)mPciOptionRomTable.PciOptionRomCount]); + + TempPciOptionRomDescriptors->RomAddress = RomBuffer; + TempPciOptionRomDescriptors->MemoryType = EfiBootServicesData; + TempPciOptionRomDescriptors->RomLength = RomBarSize; + TempPciOptionRomDescriptors->Seg = (UINT32)IoDev->SegmentNumber; + TempPciOptionRomDescriptors->Bus = (UINT8)Bus; + TempPciOptionRomDescriptors->Dev = (UINT8)Device; + TempPciOptionRomDescriptors->Func = (UINT8)Func; + TempPciOptionRomDescriptors->ExecutedLegacyBiosImage = TRUE; + TempPciOptionRomDescriptors->DontLoadEfiRom = FALSE; + + mPciOptionRomTable.PciOptionRomCount++; + } + } + + // + // Disable the Memory decode for the PCI-PCI Bridge + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + Register &= (~0x02); + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + } + } + } + + // + // Restore the PCI Configuration Header + // + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader); +} + +VOID +SaveCommandRegister ( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + UINT16 Bus, + UINT16 Device, + UINT16 Func, + IN VOID *VoidContext + ) + +{ + PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context; + UINT64 Address; + UINTN Index; + UINT16 Command; + + Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext; + + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4); + + Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func; + + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]); + + // + // Clear the memory enable bit + // + Command = (UINT16) (Context->CommandRegisterBuffer[Index] & (~0x02)); + + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Command); +} + +VOID +RestoreCommandRegister ( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + UINT16 Bus, + UINT16 Device, + UINT16 Func, + IN VOID *VoidContext + ) + +{ + PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context; + UINT64 Address; + UINTN Index; + + Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext; + + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4); + + Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func; + + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]); +} + +EFI_STATUS +ScanPciRootBridgeForRoms( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev + ) + +{ + EFI_STATUS Status; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; + UINT16 MinBus; + UINT16 MaxBus; + UINT64 RootWindowBase; + UINT64 RootWindowLimit; + PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT Context; + + if (mPciOptionRomTableInstalled == FALSE) { + gBS->InstallConfigurationTable(&gEfiPciOptionRomTableGuid, &mPciOptionRomTable); + mPciOptionRomTableInstalled = TRUE; + } + + Status = IoDev->Configuration(IoDev, (VOID **) &Descriptors); + if (EFI_ERROR (Status) || Descriptors == NULL) { + return EFI_NOT_FOUND; + } + + MinBus = 0xffff; + MaxBus = 0xffff; + RootWindowBase = 0; + RootWindowLimit = 0; + while (Descriptors->Desc != ACPI_END_TAG_DESCRIPTOR) { + // + // Find bus range + // + if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) { + MinBus = (UINT16)Descriptors->AddrRangeMin; + MaxBus = (UINT16)Descriptors->AddrRangeMax; + } + // + // Find memory descriptors that are not prefetchable + // + if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM && Descriptors->SpecificFlag == 0) { + // + // Find Memory Descriptors that are less than 4GB, so the PPB Memory Window can be used for downstream devices + // + if (Descriptors->AddrRangeMax < 0x100000000ULL) { + // + // Find the largest Non-Prefetchable Memory Descriptor that is less than 4GB + // + if ((Descriptors->AddrRangeMax - Descriptors->AddrRangeMin) > (RootWindowLimit - RootWindowBase)) { + RootWindowBase = Descriptors->AddrRangeMin; + RootWindowLimit = Descriptors->AddrRangeMax; + } + } + } + Descriptors ++; + } + + // + // Make sure a bus range was found + // + if (MinBus == 0xffff || MaxBus == 0xffff) { + return EFI_NOT_FOUND; + } + + // + // Make sure a non-prefetchable memory region was found + // + if (RootWindowBase == 0 && RootWindowLimit == 0) { + return EFI_NOT_FOUND; + } + + // + // Round the Base and Limit values to 1 MB boudaries + // + RootWindowBase = ((RootWindowBase - 1) & 0xfff00000) + 0x00100000; + RootWindowLimit = ((RootWindowLimit + 1) & 0xfff00000) - 1; + + // + // Make sure that the size of the rounded window is greater than zero + // + if (RootWindowLimit <= RootWindowBase) { + return EFI_NOT_FOUND; + } + + // + // Allocate buffer to save the Command register from all the PCI devices + // + Context.CommandRegisterBuffer = NULL; + Status = gBS->AllocatePool( + EfiBootServicesData, + sizeof(UINT16) * (MaxBus - MinBus + 1) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1), + (VOID **) &Context.CommandRegisterBuffer + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Context.PpbMemoryWindow = (((UINT32)RootWindowBase) >> 16) | ((UINT32)RootWindowLimit & 0xffff0000); + + // + // Save the Command register from all the PCI devices, and disable the I/O, Mem, and BusMaster bits + // + ScanPciBus( + IoDev, + MinBus, MaxBus, + 0, PCI_MAX_DEVICE, + 0, PCI_MAX_FUNC, + SaveCommandRegister, &Context + ); + + // + // Recursively scan all the busses for PCI Option ROMs + // + ScanPciBus( + IoDev, + MinBus, MinBus, + 0, PCI_MAX_DEVICE, + 0, PCI_MAX_FUNC, + CheckForRom, &Context + ); + + // + // Restore the Command register in all the PCI devices + // + ScanPciBus( + IoDev, + MinBus, MaxBus, + 0, PCI_MAX_DEVICE, + 0, PCI_MAX_FUNC, + RestoreCommandRegister, &Context + ); + + // + // Free the buffer used to save all the Command register values + // + gBS->FreePool(Context.CommandRegisterBuffer); + + return EFI_SUCCESS; +} diff --git a/CorebootModulePkg/SataControllerDxe/ComponentName.c b/CorebootModulePkg/SataControllerDxe/ComponentName.c new file mode 100644 index 0000000000..c470cd4d12 --- /dev/null +++ b/CorebootModulePkg/SataControllerDxe/ComponentName.c @@ -0,0 +1,176 @@ +/** @file + UEFI Component Name(2) protocol implementation for Sata Controller driver. + + Copyright (c) 2011, 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. + +**/ + +#include "SataController.h" + +// +/// EFI Component Name Protocol +/// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSataControllerComponentName = { + SataControllerComponentNameGetDriverName, + SataControllerComponentNameGetControllerName, + "eng" +}; + +// +/// EFI Component Name 2 Protocol +/// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSataControllerComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SataControllerComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SataControllerComponentNameGetControllerName, + "en" +}; + +// +/// Driver Name Strings +/// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSataControllerDriverNameTable[] = { + { + "eng;en", + (CHAR16 *)L"Sata Controller Init Driver" + }, + { + NULL, + NULL + } +}; + +/// +/// Controller Name Strings +/// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSataControllerControllerNameTable[] = { + { + "eng;en", + (CHAR16 *)L"Sata Controller" + }, + { + NULL, + NULL + } +}; + +/** + Retrieves a Unicode string that is the user readable name of the UEFI Driver. + + @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + @param Language A pointer to a three character ISO 639-2 language identifier. + This is the language of the driver name that that the caller + is requesting, and it must match one of the languages specified + in SupportedLanguages. The number of languages supported by a + driver is up to the driver writer. + @param DriverName A pointer to the Unicode string to return. This Unicode string + is the name of the driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER DriverName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This does not support the + language specified by Language. +**/ +EFI_STATUS +EFIAPI +SataControllerComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mSataControllerDriverNameTable, + DriverName, + (BOOLEAN)(This == &gSataControllerComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an UEFI Driver. + + @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + @param ControllerHandle The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + @param ChildHandle OPTIONAL The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + @param Language A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + @param ControllerName A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language + specified by Language from the point of view of the + driver specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + @retval EFI_UNSUPPORTED The driver specified by This does not support the + language specified by Language. +**/ +EFI_STATUS +EFIAPI +SataControllerComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + + // + // Make sure this driver is currently managing ControllHandle + // + Status = EfiTestManagedDevice ( + ControllerHandle, + gSataControllerDriverBinding.DriverBindingHandle, + &gEfiPciIoProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mSataControllerControllerNameTable, + ControllerName, + (BOOLEAN)(This == &gSataControllerComponentName) + ); +} diff --git a/CorebootModulePkg/SataControllerDxe/SataController.c b/CorebootModulePkg/SataControllerDxe/SataController.c new file mode 100644 index 0000000000..d35c6c3367 --- /dev/null +++ b/CorebootModulePkg/SataControllerDxe/SataController.c @@ -0,0 +1,1049 @@ +/** @file + This driver module produces IDE_CONTROLLER_INIT protocol for Sata Controllers. + + Copyright (c) 2011, 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. + +**/ + +#include "SataController.h" + +/// +/// EFI_DRIVER_BINDING_PROTOCOL instance +/// +EFI_DRIVER_BINDING_PROTOCOL gSataControllerDriverBinding = { + SataControllerSupported, + SataControllerStart, + SataControllerStop, + 0xa, + NULL, + NULL +}; + +/** + Read AHCI Operation register. + + @param PciIo The PCI IO protocol instance. + @param Offset The operation register offset. + + @return The register content read. + +**/ +UINT32 +EFIAPI +AhciReadReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 Offset + ) +{ + UINT32 Data; + + ASSERT (PciIo != NULL); + + Data = 0; + + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint32, + AHCI_BAR_INDEX, + (UINT64) Offset, + 1, + &Data + ); + + return Data; +} + +/** + Write AHCI Operation register. + + @param PciIo The PCI IO protocol instance. + @param Offset The operation register offset. + @param Data The data used to write down. + +**/ +VOID +EFIAPI +AhciWriteReg ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT32 Offset, + IN UINT32 Data + ) +{ + ASSERT (PciIo != NULL); + + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint32, + AHCI_BAR_INDEX, + (UINT64) Offset, + 1, + &Data + ); + + return; +} + +/** + This function is used to calculate the best PIO mode supported by specific IDE device + + @param IdentifyData The identify data of specific IDE device. + @param DisPioMode Disqualified PIO modes collection. + @param SelectedMode Available PIO modes collection. + + @retval EFI_SUCCESS Best PIO modes are returned. + @retval EFI_UNSUPPORTED The device doesn't support PIO mode, + or all supported modes have been disqualified. +**/ +EFI_STATUS +CalculateBestPioMode ( + IN EFI_IDENTIFY_DATA *IdentifyData, + IN UINT16 *DisPioMode OPTIONAL, + OUT UINT16 *SelectedMode + ) +{ + UINT16 PioMode; + UINT16 AdvancedPioMode; + UINT16 Temp; + UINT16 Index; + UINT16 MinimumPioCycleTime; + + Temp = 0xff; + + PioMode = (UINT8) (((ATA5_IDENTIFY_DATA *) (&(IdentifyData->AtaData)))->pio_cycle_timing >> 8); + + // + // See whether Identify Data word 64 - 70 are valid + // + if ((IdentifyData->AtaData.field_validity & 0x02) == 0x02) { + + AdvancedPioMode = IdentifyData->AtaData.advanced_pio_modes; + DEBUG ((EFI_D_INFO, "CalculateBestPioMode: AdvancedPioMode = %x\n", AdvancedPioMode)); + + for (Index = 0; Index < 8; Index++) { + if ((AdvancedPioMode & 0x01) != 0) { + Temp = Index; + } + + AdvancedPioMode >>= 1; + } + + // + // If Temp is modified, mean the advanced_pio_modes is not zero; + // if Temp is not modified, mean there is no advanced PIO mode supported, + // the best PIO Mode is the value in pio_cycle_timing. + // + if (Temp != 0xff) { + AdvancedPioMode = (UINT16) (Temp + 3); + } else { + AdvancedPioMode = PioMode; + } + + // + // Limit the PIO mode to at most PIO4. + // + PioMode = (UINT16) MIN (AdvancedPioMode, 4); + + MinimumPioCycleTime = IdentifyData->AtaData.min_pio_cycle_time_with_flow_control; + + if (MinimumPioCycleTime <= 120) { + PioMode = (UINT16) MIN (4, PioMode); + } else if (MinimumPioCycleTime <= 180) { + PioMode = (UINT16) MIN (3, PioMode); + } else if (MinimumPioCycleTime <= 240) { + PioMode = (UINT16) MIN (2, PioMode); + } else { + PioMode = 0; + } + + // + // Degrade the PIO mode if the mode has been disqualified + // + if (DisPioMode != NULL) { + if (*DisPioMode < 2) { + return EFI_UNSUPPORTED; // no mode below ATA_PIO_MODE_BELOW_2 + } + + if (PioMode >= *DisPioMode) { + PioMode = (UINT16) (*DisPioMode - 1); + } + } + + if (PioMode < 2) { + *SelectedMode = 1; // ATA_PIO_MODE_BELOW_2; + } else { + *SelectedMode = PioMode; // ATA_PIO_MODE_2 to ATA_PIO_MODE_4; + } + + } else { + // + // Identify Data word 64 - 70 are not valid + // Degrade the PIO mode if the mode has been disqualified + // + if (DisPioMode != NULL) { + if (*DisPioMode < 2) { + return EFI_UNSUPPORTED; // no mode below ATA_PIO_MODE_BELOW_2 + } + + if (PioMode == *DisPioMode) { + PioMode--; + } + } + + if (PioMode < 2) { + *SelectedMode = 1; // ATA_PIO_MODE_BELOW_2; + } else { + *SelectedMode = 2; // ATA_PIO_MODE_2; + } + + } + + return EFI_SUCCESS; +} + +/** + This function is used to calculate the best UDMA mode supported by specific IDE device + + @param IdentifyData The identify data of specific IDE device. + @param DisUDmaMode Disqualified UDMA modes collection. + @param SelectedMode Available UDMA modes collection. + + @retval EFI_SUCCESS Best UDMA modes are returned. + @retval EFI_UNSUPPORTED The device doesn't support UDMA mode, + or all supported modes have been disqualified. +**/ +EFI_STATUS +CalculateBestUdmaMode ( + IN EFI_IDENTIFY_DATA *IdentifyData, + IN UINT16 *DisUDmaMode OPTIONAL, + OUT UINT16 *SelectedMode + ) +{ + UINT16 TempMode; + UINT16 DeviceUDmaMode; + + DeviceUDmaMode = 0; + + // + // Check whether the WORD 88 (supported UltraDMA by drive) is valid + // + if ((IdentifyData->AtaData.field_validity & 0x04) == 0x00) { + return EFI_UNSUPPORTED; + } + + DeviceUDmaMode = IdentifyData->AtaData.ultra_dma_mode; + DEBUG ((EFI_D_INFO, "CalculateBestUdmaMode: DeviceUDmaMode = %x\n", DeviceUDmaMode)); + DeviceUDmaMode &= 0x3f; + TempMode = 0; // initialize it to UDMA-0 + + while ((DeviceUDmaMode >>= 1) != 0) { + TempMode++; + } + + // + // Degrade the UDMA mode if the mode has been disqualified + // + if (DisUDmaMode != NULL) { + if (*DisUDmaMode == 0) { + *SelectedMode = 0; + return EFI_UNSUPPORTED; // no mode below ATA_UDMA_MODE_0 + } + + if (TempMode >= *DisUDmaMode) { + TempMode = (UINT16) (*DisUDmaMode - 1); + } + } + + // + // Possible returned mode is between ATA_UDMA_MODE_0 and ATA_UDMA_MODE_5 + // + *SelectedMode = TempMode; + + return EFI_SUCCESS; +} + +/** + The Entry Point of module. It follows the standard UEFI driver model. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +InitializeSataControllerDriver ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Install driver model protocol(s). + // + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gSataControllerDriverBinding, + ImageHandle, + &gSataControllerComponentName, + &gSataControllerComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + Supported function of Driver Binding protocol for this driver. + Test to see if this driver supports ControllerHandle. + + @param This Protocol instance pointer. + @param Controller Handle of device to test. + @param RemainingDevicePath A pointer to the device path. + it should be ignored by device driver. + + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_ALREADY_STARTED This driver is already running on this device. + @retval other This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +SataControllerSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE00 PciData; + + // + // Attempt to open PCI I/O Protocol + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Now further check the PCI header: Base Class (offset 0x0B) and + // Sub Class (offset 0x0A). This controller should be an SATA controller + // + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + PCI_CLASSCODE_OFFSET, + sizeof (PciData.Hdr.ClassCode), + PciData.Hdr.ClassCode + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + if (IS_PCI_IDE (&PciData) || IS_PCI_SATADPA (&PciData)) { + return EFI_SUCCESS; + } + + return EFI_UNSUPPORTED; +} + +/** + This routine is called right after the .Supported() called and + Start this driver on ControllerHandle. + + @param This Protocol instance pointer. + @param Controller Handle of device to bind driver to. + @param RemainingDevicePath A pointer to the device path. + it should be ignored by device driver. + + @retval EFI_SUCCESS This driver is added to this device. + @retval EFI_ALREADY_STARTED This driver is already running on this device. + @retval other Some error occurs when binding this driver to this device. + +**/ +EFI_STATUS +EFIAPI +SataControllerStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE00 PciData; + EFI_SATA_CONTROLLER_PRIVATE_DATA *SataPrivateData; + UINT32 Data32; + UINTN ChannelDeviceCount; + + DEBUG ((EFI_D_INFO, "SataControllerStart START\n")); + + SataPrivateData = NULL; + + // + // Now test and open PCI I/O Protocol + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "SataControllerStart error return status = %r\n", Status)); + return Status; + } + + // + // Allocate Sata Private Data structure + // + SataPrivateData = AllocateZeroPool (sizeof (EFI_SATA_CONTROLLER_PRIVATE_DATA)); + if (SataPrivateData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + // + // Initialize Sata Private Data + // + SataPrivateData->Signature = SATA_CONTROLLER_SIGNATURE; + SataPrivateData->PciIo = PciIo; + SataPrivateData->IdeInit.GetChannelInfo = IdeInitGetChannelInfo; + SataPrivateData->IdeInit.NotifyPhase = IdeInitNotifyPhase; + SataPrivateData->IdeInit.SubmitData = IdeInitSubmitData; + SataPrivateData->IdeInit.DisqualifyMode = IdeInitDisqualifyMode; + SataPrivateData->IdeInit.CalculateMode = IdeInitCalculateMode; + SataPrivateData->IdeInit.SetTiming = IdeInitSetTiming; + SataPrivateData->IdeInit.EnumAll = SATA_ENUMER_ALL; + + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + PCI_CLASSCODE_OFFSET, + sizeof (PciData.Hdr.ClassCode), + PciData.Hdr.ClassCode + ); + ASSERT_EFI_ERROR (Status); + + if (IS_PCI_IDE (&PciData)) { + SataPrivateData->IdeInit.ChannelCount = IDE_MAX_CHANNEL; + SataPrivateData->DeviceCount = IDE_MAX_DEVICES; + } else if (IS_PCI_SATADPA (&PciData)) { + // + // Read Host Capability Register(CAP) to get Number of Ports(NPS) and Supports Port Multiplier(SPM) + // NPS is 0's based value indicating the maximum number of ports supported by the HBA silicon. + // A maximum of 32 ports can be supported. A value of '0h', indicating one port, is the minimum requirement. + // + Data32 = AhciReadReg (PciIo, R_AHCI_CAP); + SataPrivateData->IdeInit.ChannelCount = (UINT8) ((Data32 & B_AHCI_CAP_NPS) + 1); + SataPrivateData->DeviceCount = AHCI_MAX_DEVICES; + if ((Data32 & B_AHCI_CAP_SPM) == B_AHCI_CAP_SPM) { + SataPrivateData->DeviceCount = AHCI_MULTI_MAX_DEVICES; + } + } + + ChannelDeviceCount = (UINTN) (SataPrivateData->IdeInit.ChannelCount) * (UINTN) (SataPrivateData->DeviceCount); + SataPrivateData->DisqualifiedModes = AllocateZeroPool ((sizeof (EFI_ATA_COLLECTIVE_MODE)) * ChannelDeviceCount); + if (SataPrivateData->DisqualifiedModes == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + SataPrivateData->IdentifyData = AllocateZeroPool ((sizeof (EFI_IDENTIFY_DATA)) * ChannelDeviceCount); + if (SataPrivateData->IdentifyData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + SataPrivateData->IdentifyValid = AllocateZeroPool ((sizeof (BOOLEAN)) * ChannelDeviceCount); + if (SataPrivateData->IdentifyValid == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + // + // Install IDE Controller Init Protocol to this instance + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &Controller, + &gEfiIdeControllerInitProtocolGuid, + &(SataPrivateData->IdeInit), + NULL + ); + +Done: + if (EFI_ERROR (Status)) { + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + if (SataPrivateData != NULL) { + if (SataPrivateData->DisqualifiedModes != NULL) { + FreePool (SataPrivateData->DisqualifiedModes); + } + if (SataPrivateData->IdentifyData != NULL) { + FreePool (SataPrivateData->IdentifyData); + } + if (SataPrivateData->IdentifyValid != NULL) { + FreePool (SataPrivateData->IdentifyValid); + } + FreePool (SataPrivateData); + } + } + + DEBUG ((EFI_D_INFO, "SataControllerStart END status = %r\n", Status)); + + return Status; +} + +/** + Stop this driver on ControllerHandle. + + @param This Protocol instance pointer. + @param Controller Handle of device to stop driver on. + @param NumberOfChildren Not used. + @param ChildHandleBuffer Not used. + + @retval EFI_SUCCESS This driver is removed from this device. + @retval other Some error occurs when removing this driver from this device. + +**/ +EFI_STATUS +EFIAPI +SataControllerStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status; + EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit; + EFI_SATA_CONTROLLER_PRIVATE_DATA *SataPrivateData; + + // + // Open the produced protocol + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiIdeControllerInitProtocolGuid, + (VOID **) &IdeInit, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + SataPrivateData = SATA_CONTROLLER_PRIVATE_DATA_FROM_THIS (IdeInit); + ASSERT (SataPrivateData != NULL); + + // + // Uninstall the IDE Controller Init Protocol from this instance + // + Status = gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiIdeControllerInitProtocolGuid, + &(SataPrivateData->IdeInit), + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (SataPrivateData != NULL) { + if (SataPrivateData->DisqualifiedModes != NULL) { + FreePool (SataPrivateData->DisqualifiedModes); + } + if (SataPrivateData->IdentifyData != NULL) { + FreePool (SataPrivateData->IdentifyData); + } + if (SataPrivateData->IdentifyValid != NULL) { + FreePool (SataPrivateData->IdentifyValid); + } + FreePool (SataPrivateData); + } + + // + // Close protocols opened by Sata Controller driver + // + return gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); +} + +/** + Calculate the flat array subscript of a (Channel, Device) pair. + + @param[in] SataPrivateData The private data structure corresponding to the + SATA controller that attaches the device for + which the flat array subscript is being + calculated. + + @param[in] Channel The channel (ie. port) number on the SATA + controller that the device is attached to. + + @param[in] Device The device number on the channel. + + @return The flat array subscript suitable for indexing DisqualifiedModes, + IdentifyData, and IdentifyValid. +**/ +STATIC +UINTN +FlatDeviceIndex ( + IN CONST EFI_SATA_CONTROLLER_PRIVATE_DATA *SataPrivateData, + IN UINTN Channel, + IN UINTN Device + ) +{ + ASSERT (SataPrivateData != NULL); + ASSERT (Channel < SataPrivateData->IdeInit.ChannelCount); + ASSERT (Device < SataPrivateData->DeviceCount); + + return Channel * SataPrivateData->DeviceCount + Device; +} + +// +// Interface functions of IDE_CONTROLLER_INIT protocol +// +/** + Returns the information about the specified IDE channel. + + This function can be used to obtain information about a particular IDE channel. + The driver entity uses this information during the enumeration process. + + If Enabled is set to FALSE, the driver entity will not scan the channel. Note + that it will not prevent an operating system driver from scanning the channel. + + For most of today's controllers, MaxDevices will either be 1 or 2. For SATA + controllers, this value will always be 1. SATA configurations can contain SATA + port multipliers. SATA port multipliers behave like SATA bridges and can support + up to 16 devices on the other side. If a SATA port out of the IDE controller + is connected to a port multiplier, MaxDevices will be set to the number of SATA + devices that the port multiplier supports. Because today's port multipliers + support up to fifteen SATA devices, this number can be as large as fifteen. The IDE + bus driver is required to scan for the presence of port multipliers behind an SATA + controller and enumerate up to MaxDevices number of devices behind the port + multiplier. + + In this context, the devices behind a port multiplier constitute a channel. + + @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Channel Zero-based channel number. + @param[out] Enabled TRUE if this channel is enabled. Disabled channels + are not scanned to see if any devices are present. + @param[out] MaxDevices The maximum number of IDE devices that the bus driver + can expect on this channel. For the ATA/ATAPI + specification, version 6, this number will either be + one or two. For Serial ATA (SATA) configurations with a + port multiplier, this number can be as large as fifteen. + + @retval EFI_SUCCESS Information was returned without any errors. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + +**/ +EFI_STATUS +EFIAPI +IdeInitGetChannelInfo ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN UINT8 Channel, + OUT BOOLEAN *Enabled, + OUT UINT8 *MaxDevices + ) +{ + EFI_SATA_CONTROLLER_PRIVATE_DATA *SataPrivateData; + SataPrivateData = SATA_CONTROLLER_PRIVATE_DATA_FROM_THIS (This); + ASSERT (SataPrivateData != NULL); + + if (Channel < This->ChannelCount) { + *Enabled = TRUE; + *MaxDevices = SataPrivateData->DeviceCount; + return EFI_SUCCESS; + } + + *Enabled = FALSE; + return EFI_INVALID_PARAMETER; +} + +/** + The notifications from the driver entity that it is about to enter a certain + phase of the IDE channel enumeration process. + + This function can be used to notify the IDE controller driver to perform + specific actions, including any chipset-specific initialization, so that the + chipset is ready to enter the next phase. Seven notification points are defined + at this time. + + More synchronization points may be added as required in the future. + + @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Phase The phase during enumeration. + @param[in] Channel Zero-based channel number. + + @retval EFI_SUCCESS The notification was accepted without any errors. + @retval EFI_UNSUPPORTED Phase is not supported. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + @retval EFI_NOT_READY This phase cannot be entered at this time; for + example, an attempt was made to enter a Phase + without having entered one or more previous + Phase. + +**/ +EFI_STATUS +EFIAPI +IdeInitNotifyPhase ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN EFI_IDE_CONTROLLER_ENUM_PHASE Phase, + IN UINT8 Channel + ) +{ + return EFI_SUCCESS; +} + +/** + Submits the device information to the IDE controller driver. + + This function is used by the driver entity to pass detailed information about + a particular device to the IDE controller driver. The driver entity obtains + this information by issuing an ATA or ATAPI IDENTIFY_DEVICE command. IdentifyData + is the pointer to the response data buffer. The IdentifyData buffer is owned + by the driver entity, and the IDE controller driver must make a local copy + of the entire buffer or parts of the buffer as needed. The original IdentifyData + buffer pointer may not be valid when + + - EFI_IDE_CONTROLLER_INIT_PROTOCOL.CalculateMode() or + - EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode() is called at a later point. + + The IDE controller driver may consult various fields of EFI_IDENTIFY_DATA to + compute the optimum mode for the device. These fields are not limited to the + timing information. For example, an implementation of the IDE controller driver + may examine the vendor and type/mode field to match known bad drives. + + The driver entity may submit drive information in any order, as long as it + submits information for all the devices belonging to the enumeration group + before EFI_IDE_CONTROLLER_INIT_PROTOCOL.CalculateMode() is called for any device + in that enumeration group. If a device is absent, EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() + should be called with IdentifyData set to NULL. The IDE controller driver may + not have any other mechanism to know whether a device is present or not. Therefore, + setting IdentifyData to NULL does not constitute an error condition. + EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() can be called only once for a + given (Channel, Device) pair. + + @param[in] This A pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Channel Zero-based channel number. + @param[in] Device Zero-based device number on the Channel. + @param[in] IdentifyData The device's response to the ATA IDENTIFY_DEVICE command. + + @retval EFI_SUCCESS The information was accepted without any errors. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + @retval EFI_INVALID_PARAMETER Device is invalid. + +**/ +EFI_STATUS +EFIAPI +IdeInitSubmitData ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN UINT8 Channel, + IN UINT8 Device, + IN EFI_IDENTIFY_DATA *IdentifyData + ) +{ + EFI_SATA_CONTROLLER_PRIVATE_DATA *SataPrivateData; + UINTN DeviceIndex; + + SataPrivateData = SATA_CONTROLLER_PRIVATE_DATA_FROM_THIS (This); + ASSERT (SataPrivateData != NULL); + + if ((Channel >= This->ChannelCount) || (Device >= SataPrivateData->DeviceCount)) { + return EFI_INVALID_PARAMETER; + } + + DeviceIndex = FlatDeviceIndex (SataPrivateData, Channel, Device); + + // + // Make a local copy of device's IdentifyData and mark the valid flag + // + if (IdentifyData != NULL) { + CopyMem ( + &(SataPrivateData->IdentifyData[DeviceIndex]), + IdentifyData, + sizeof (EFI_IDENTIFY_DATA) + ); + + SataPrivateData->IdentifyValid[DeviceIndex] = TRUE; + } else { + SataPrivateData->IdentifyValid[DeviceIndex] = FALSE; + } + + return EFI_SUCCESS; +} + +/** + Disqualifies specific modes for an IDE device. + + This function allows the driver entity or other drivers (such as platform + drivers) to reject certain timing modes and request the IDE controller driver + to recalculate modes. This function allows the driver entity and the IDE + controller driver to negotiate the timings on a per-device basis. This function + is useful in the case of drives that lie about their capabilities. An example + is when the IDE device fails to accept the timing modes that are calculated + by the IDE controller driver based on the response to the Identify Drive command. + + If the driver entity does not want to limit the ATA timing modes and leave that + decision to the IDE controller driver, it can either not call this function for + the given device or call this function and set the Valid flag to FALSE for all + modes that are listed in EFI_ATA_COLLECTIVE_MODE. + + The driver entity may disqualify modes for a device in any order and any number + of times. + + This function can be called multiple times to invalidate multiple modes of the + same type (e.g., Programmed Input/Output [PIO] modes 3 and 4). See the ATA/ATAPI + specification for more information on PIO modes. + + For Serial ATA (SATA) controllers, this member function can be used to disqualify + a higher transfer rate mode on a given channel. For example, a platform driver + may inform the IDE controller driver to not use second-generation (Gen2) speeds + for a certain SATA drive. + + @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Channel The zero-based channel number. + @param[in] Device The zero-based device number on the Channel. + @param[in] BadModes The modes that the device does not support and that + should be disqualified. + + @retval EFI_SUCCESS The modes were accepted without any errors. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + @retval EFI_INVALID_PARAMETER Device is invalid. + @retval EFI_INVALID_PARAMETER IdentifyData is NULL. + +**/ +EFI_STATUS +EFIAPI +IdeInitDisqualifyMode ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN UINT8 Channel, + IN UINT8 Device, + IN EFI_ATA_COLLECTIVE_MODE *BadModes + ) +{ + EFI_SATA_CONTROLLER_PRIVATE_DATA *SataPrivateData; + UINTN DeviceIndex; + + SataPrivateData = SATA_CONTROLLER_PRIVATE_DATA_FROM_THIS (This); + ASSERT (SataPrivateData != NULL); + + if ((Channel >= This->ChannelCount) || (BadModes == NULL) || (Device >= SataPrivateData->DeviceCount)) { + return EFI_INVALID_PARAMETER; + } + + DeviceIndex = FlatDeviceIndex (SataPrivateData, Channel, Device); + + // + // Record the disqualified modes per channel per device. From ATA/ATAPI spec, + // if a mode is not supported, the modes higher than it is also not supported. + // + CopyMem ( + &(SataPrivateData->DisqualifiedModes[DeviceIndex]), + BadModes, + sizeof (EFI_ATA_COLLECTIVE_MODE) + ); + + return EFI_SUCCESS; +} + +/** + Returns the information about the optimum modes for the specified IDE device. + + This function is used by the driver entity to obtain the optimum ATA modes for + a specific device. The IDE controller driver takes into account the following + while calculating the mode: + - The IdentifyData inputs to EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() + - The BadModes inputs to EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode() + + The driver entity is required to call EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() + for all the devices that belong to an enumeration group before calling + EFI_IDE_CONTROLLER_INIT_PROTOCOL.CalculateMode() for any device in the same group. + + The IDE controller driver will use controller- and possibly platform-specific + algorithms to arrive at SupportedModes. The IDE controller may base its + decision on user preferences and other considerations as well. This function + may be called multiple times because the driver entity may renegotiate the mode + with the IDE controller driver using EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode(). + + The driver entity may collect timing information for various devices in any + order. The driver entity is responsible for making sure that all the dependencies + are satisfied. For example, the SupportedModes information for device A that + was previously returned may become stale after a call to + EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode() for device B. + + The buffer SupportedModes is allocated by the callee because the caller does + not necessarily know the size of the buffer. The type EFI_ATA_COLLECTIVE_MODE + is defined in a way that allows for future extensibility and can be of variable + length. This memory pool should be deallocated by the caller when it is no + longer necessary. + + The IDE controller driver for a Serial ATA (SATA) controller can use this + member function to force a lower speed (first-generation [Gen1] speeds on a + second-generation [Gen2]-capable hardware). The IDE controller driver can + also allow the driver entity to stay with the speed that has been negotiated + by the physical layer. + + @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Channel A zero-based channel number. + @param[in] Device A zero-based device number on the Channel. + @param[out] SupportedModes The optimum modes for the device. + + @retval EFI_SUCCESS SupportedModes was returned. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + @retval EFI_INVALID_PARAMETER Device is invalid. + @retval EFI_INVALID_PARAMETER SupportedModes is NULL. + @retval EFI_NOT_READY Modes cannot be calculated due to a lack of + data. This error may happen if + EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() + and EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyData() + were not called for at least one drive in the + same enumeration group. + +**/ +EFI_STATUS +EFIAPI +IdeInitCalculateMode ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN UINT8 Channel, + IN UINT8 Device, + OUT EFI_ATA_COLLECTIVE_MODE **SupportedModes + ) +{ + EFI_SATA_CONTROLLER_PRIVATE_DATA *SataPrivateData; + EFI_IDENTIFY_DATA *IdentifyData; + BOOLEAN IdentifyValid; + EFI_ATA_COLLECTIVE_MODE *DisqualifiedModes; + UINT16 SelectedMode; + EFI_STATUS Status; + UINTN DeviceIndex; + + SataPrivateData = SATA_CONTROLLER_PRIVATE_DATA_FROM_THIS (This); + ASSERT (SataPrivateData != NULL); + + if ((Channel >= This->ChannelCount) || (SupportedModes == NULL) || (Device >= SataPrivateData->DeviceCount)) { + return EFI_INVALID_PARAMETER; + } + + *SupportedModes = AllocateZeroPool (sizeof (EFI_ATA_COLLECTIVE_MODE)); + if (*SupportedModes == NULL) { + ASSERT (*SupportedModes != NULL); + return EFI_OUT_OF_RESOURCES; + } + + DeviceIndex = FlatDeviceIndex (SataPrivateData, Channel, Device); + + IdentifyData = &(SataPrivateData->IdentifyData[DeviceIndex]); + IdentifyValid = SataPrivateData->IdentifyValid[DeviceIndex]; + DisqualifiedModes = &(SataPrivateData->DisqualifiedModes[DeviceIndex]); + + // + // Make sure we've got the valid identify data of the device from SubmitData() + // + if (!IdentifyValid) { + FreePool (*SupportedModes); + return EFI_NOT_READY; + } + + Status = CalculateBestPioMode ( + IdentifyData, + (DisqualifiedModes->PioMode.Valid ? ((UINT16 *) &(DisqualifiedModes->PioMode.Mode)) : NULL), + &SelectedMode + ); + if (!EFI_ERROR (Status)) { + (*SupportedModes)->PioMode.Valid = TRUE; + (*SupportedModes)->PioMode.Mode = SelectedMode; + + } else { + (*SupportedModes)->PioMode.Valid = FALSE; + } + DEBUG ((EFI_D_INFO, "IdeInitCalculateMode: PioMode = %x\n", (*SupportedModes)->PioMode.Mode)); + + Status = CalculateBestUdmaMode ( + IdentifyData, + (DisqualifiedModes->UdmaMode.Valid ? ((UINT16 *) &(DisqualifiedModes->UdmaMode.Mode)) : NULL), + &SelectedMode + ); + + if (!EFI_ERROR (Status)) { + (*SupportedModes)->UdmaMode.Valid = TRUE; + (*SupportedModes)->UdmaMode.Mode = SelectedMode; + + } else { + (*SupportedModes)->UdmaMode.Valid = FALSE; + } + DEBUG ((EFI_D_INFO, "IdeInitCalculateMode: UdmaMode = %x\n", (*SupportedModes)->UdmaMode.Mode)); + + // + // The modes other than PIO and UDMA are not supported + // + return EFI_SUCCESS; +} + +/** + Commands the IDE controller driver to program the IDE controller hardware + so that the specified device can operate at the specified mode. + + This function is used by the driver entity to instruct the IDE controller + driver to program the IDE controller hardware to the specified modes. This + function can be called only once for a particular device. For a Serial ATA + (SATA) Advanced Host Controller Interface (AHCI) controller, no controller- + specific programming may be required. + + @param[in] This Pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Channel Zero-based channel number. + @param[in] Device Zero-based device number on the Channel. + @param[in] Modes The modes to set. + + @retval EFI_SUCCESS The command was accepted without any errors. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + @retval EFI_INVALID_PARAMETER Device is invalid. + @retval EFI_NOT_READY Modes cannot be set at this time due to lack of data. + @retval EFI_DEVICE_ERROR Modes cannot be set due to hardware failure. + The driver entity should not use this device. + +**/ +EFI_STATUS +EFIAPI +IdeInitSetTiming ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN UINT8 Channel, + IN UINT8 Device, + IN EFI_ATA_COLLECTIVE_MODE *Modes + ) +{ + return EFI_SUCCESS; +} diff --git a/CorebootModulePkg/SataControllerDxe/SataController.h b/CorebootModulePkg/SataControllerDxe/SataController.h new file mode 100644 index 0000000000..e76df748d7 --- /dev/null +++ b/CorebootModulePkg/SataControllerDxe/SataController.h @@ -0,0 +1,542 @@ +/** @file + Header file for Sata Controller driver. + + Copyright (c) 2011, 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. + +**/ + +#ifndef _SATA_CONTROLLER_H_ +#define _SATA_CONTROLLER_H_ + +#include <Uefi.h> +#include <Protocol/ComponentName.h> +#include <Protocol/DriverBinding.h> +#include <Protocol/PciIo.h> +#include <Protocol/IdeControllerInit.h> +#include <Library/UefiDriverEntryPoint.h> +#include <Library/DebugLib.h> +#include <Library/UefiLib.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <IndustryStandard/Pci.h> + +// +// Global Variables definitions +// +extern EFI_DRIVER_BINDING_PROTOCOL gSataControllerDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gSataControllerComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gSataControllerComponentName2; + +#define AHCI_BAR_INDEX 0x05 +#define R_AHCI_CAP 0x0 +#define B_AHCI_CAP_NPS (BIT4 | BIT3 | BIT2 | BIT1 | BIT0) // Number of Ports +#define B_AHCI_CAP_SPM BIT17 // Supports Port Multiplier + +/// +/// AHCI each channel can have up to 1 device +/// +#define AHCI_MAX_DEVICES 0x01 + +/// +/// AHCI each channel can have 15 devices in the presence of a multiplier +/// +#define AHCI_MULTI_MAX_DEVICES 0x0F + +/// +/// IDE supports 2 channel max +/// +#define IDE_MAX_CHANNEL 0x02 + +/// +/// IDE supports 2 devices max +/// +#define IDE_MAX_DEVICES 0x02 + +#define SATA_ENUMER_ALL FALSE + +// +// Sata Controller driver private data structure +// + +#define SATA_CONTROLLER_SIGNATURE SIGNATURE_32('S','A','T','A') + +typedef struct _EFI_SATA_CONTROLLER_PRIVATE_DATA { + // + // Standard signature used to identify Sata Controller private data + // + UINT32 Signature; + + // + // Protocol instance of IDE_CONTROLLER_INIT produced by this driver + // + EFI_IDE_CONTROLLER_INIT_PROTOCOL IdeInit; + + // + // Copy of protocol pointers used by this driver + // + EFI_PCI_IO_PROTOCOL *PciIo; + + // + // The number of devices that are supported by this channel + // + UINT8 DeviceCount; + + // + // The highest disqulified mode for each attached device, + // From ATA/ATAPI spec, if a mode is not supported, + // the modes higher than it is also not supported + // + EFI_ATA_COLLECTIVE_MODE *DisqualifiedModes; + + // + // A copy of EFI_IDENTIFY_DATA data for each attached SATA device and its flag + // + EFI_IDENTIFY_DATA *IdentifyData; + BOOLEAN *IdentifyValid; +} EFI_SATA_CONTROLLER_PRIVATE_DATA; + +#define SATA_CONTROLLER_PRIVATE_DATA_FROM_THIS(a) CR(a, EFI_SATA_CONTROLLER_PRIVATE_DATA, IdeInit, SATA_CONTROLLER_SIGNATURE) + +// +// Driver binding functions declaration +// +/** + Supported function of Driver Binding protocol for this driver. + Test to see if this driver supports ControllerHandle. + + @param This Protocol instance pointer. + @param Controller Handle of device to test. + @param RemainingDevicePath A pointer to the device path. Should be ignored by + device driver. + + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_ALREADY_STARTED This driver is already running on this device. + @retval other This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +SataControllerSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + +/** + This routine is called right after the .Supported() called and + Start this driver on ControllerHandle. + + @param This Protocol instance pointer. + @param Controller Handle of device to bind driver to. + @param RemainingDevicePath A pointer to the device path. Should be ignored by + device driver. + + @retval EFI_SUCCESS This driver is added to this device. + @retval EFI_ALREADY_STARTED This driver is already running on this device. + @retval other Some error occurs when binding this driver to this device. + +**/ +EFI_STATUS +EFIAPI +SataControllerStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +; + +/** + Stop this driver on ControllerHandle. + + @param This Protocol instance pointer. + @param Controller Handle of device to stop driver on. + @param NumberOfChildren Not used. + @param ChildHandleBuffer Not used. + + @retval EFI_SUCCESS This driver is removed from this device. + @retval other Some error occurs when removing this driver from this device. + +**/ +EFI_STATUS +EFIAPI +SataControllerStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +; + +// +// IDE controller init functions declaration +// +/** + Returns the information about the specified IDE channel. + + This function can be used to obtain information about a particular IDE channel. + The driver entity uses this information during the enumeration process. + + If Enabled is set to FALSE, the driver entity will not scan the channel. Note + that it will not prevent an operating system driver from scanning the channel. + + For most of today's controllers, MaxDevices will either be 1 or 2. For SATA + controllers, this value will always be 1. SATA configurations can contain SATA + port multipliers. SATA port multipliers behave like SATA bridges and can support + up to 16 devices on the other side. If a SATA port out of the IDE controller + is connected to a port multiplier, MaxDevices will be set to the number of SATA + devices that the port multiplier supports. Because today's port multipliers + support up to fifteen SATA devices, this number can be as large as fifteen. The IDE + bus driver is required to scan for the presence of port multipliers behind an SATA + controller and enumerate up to MaxDevices number of devices behind the port + multiplier. + + In this context, the devices behind a port multiplier constitute a channel. + + @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Channel Zero-based channel number. + @param[out] Enabled TRUE if this channel is enabled. Disabled channels + are not scanned to see if any devices are present. + @param[out] MaxDevices The maximum number of IDE devices that the bus driver + can expect on this channel. For the ATA/ATAPI + specification, version 6, this number will either be + one or two. For Serial ATA (SATA) configurations with a + port multiplier, this number can be as large as fifteen. + + @retval EFI_SUCCESS Information was returned without any errors. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + +**/ +EFI_STATUS +EFIAPI +IdeInitGetChannelInfo ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN UINT8 Channel, + OUT BOOLEAN *Enabled, + OUT UINT8 *MaxDevices + ) +; + +/** + The notifications from the driver entity that it is about to enter a certain + phase of the IDE channel enumeration process. + + This function can be used to notify the IDE controller driver to perform + specific actions, including any chipset-specific initialization, so that the + chipset is ready to enter the next phase. Seven notification points are defined + at this time. + + More synchronization points may be added as required in the future. + + @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Phase The phase during enumeration. + @param[in] Channel Zero-based channel number. + + @retval EFI_SUCCESS The notification was accepted without any errors. + @retval EFI_UNSUPPORTED Phase is not supported. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + @retval EFI_NOT_READY This phase cannot be entered at this time; for + example, an attempt was made to enter a Phase + without having entered one or more previous + Phase. + +**/ +EFI_STATUS +EFIAPI +IdeInitNotifyPhase ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN EFI_IDE_CONTROLLER_ENUM_PHASE Phase, + IN UINT8 Channel + ) +; + +/** + Submits the device information to the IDE controller driver. + + This function is used by the driver entity to pass detailed information about + a particular device to the IDE controller driver. The driver entity obtains + this information by issuing an ATA or ATAPI IDENTIFY_DEVICE command. IdentifyData + is the pointer to the response data buffer. The IdentifyData buffer is owned + by the driver entity, and the IDE controller driver must make a local copy + of the entire buffer or parts of the buffer as needed. The original IdentifyData + buffer pointer may not be valid when + + - EFI_IDE_CONTROLLER_INIT_PROTOCOL.CalculateMode() or + - EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode() is called at a later point. + + The IDE controller driver may consult various fields of EFI_IDENTIFY_DATA to + compute the optimum mode for the device. These fields are not limited to the + timing information. For example, an implementation of the IDE controller driver + may examine the vendor and type/mode field to match known bad drives. + + The driver entity may submit drive information in any order, as long as it + submits information for all the devices belonging to the enumeration group + before EFI_IDE_CONTROLLER_INIT_PROTOCOL.CalculateMode() is called for any device + in that enumeration group. If a device is absent, EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() + should be called with IdentifyData set to NULL. The IDE controller driver may + not have any other mechanism to know whether a device is present or not. Therefore, + setting IdentifyData to NULL does not constitute an error condition. + EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() can be called only once for a + given (Channel, Device) pair. + + @param[in] This A pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Channel Zero-based channel number. + @param[in] Device Zero-based device number on the Channel. + @param[in] IdentifyData The device's response to the ATA IDENTIFY_DEVICE command. + + @retval EFI_SUCCESS The information was accepted without any errors. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + @retval EFI_INVALID_PARAMETER Device is invalid. + +**/ +EFI_STATUS +EFIAPI +IdeInitSubmitData ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN UINT8 Channel, + IN UINT8 Device, + IN EFI_IDENTIFY_DATA *IdentifyData + ) +; + +/** + Disqualifies specific modes for an IDE device. + + This function allows the driver entity or other drivers (such as platform + drivers) to reject certain timing modes and request the IDE controller driver + to recalculate modes. This function allows the driver entity and the IDE + controller driver to negotiate the timings on a per-device basis. This function + is useful in the case of drives that lie about their capabilities. An example + is when the IDE device fails to accept the timing modes that are calculated + by the IDE controller driver based on the response to the Identify Drive command. + + If the driver entity does not want to limit the ATA timing modes and leave that + decision to the IDE controller driver, it can either not call this function for + the given device or call this function and set the Valid flag to FALSE for all + modes that are listed in EFI_ATA_COLLECTIVE_MODE. + + The driver entity may disqualify modes for a device in any order and any number + of times. + + This function can be called multiple times to invalidate multiple modes of the + same type (e.g., Programmed Input/Output [PIO] modes 3 and 4). See the ATA/ATAPI + specification for more information on PIO modes. + + For Serial ATA (SATA) controllers, this member function can be used to disqualify + a higher transfer rate mode on a given channel. For example, a platform driver + may inform the IDE controller driver to not use second-generation (Gen2) speeds + for a certain SATA drive. + + @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Channel The zero-based channel number. + @param[in] Device The zero-based device number on the Channel. + @param[in] BadModes The modes that the device does not support and that + should be disqualified. + + @retval EFI_SUCCESS The modes were accepted without any errors. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + @retval EFI_INVALID_PARAMETER Device is invalid. + @retval EFI_INVALID_PARAMETER IdentifyData is NULL. + +**/ +EFI_STATUS +EFIAPI +IdeInitDisqualifyMode ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN UINT8 Channel, + IN UINT8 Device, + IN EFI_ATA_COLLECTIVE_MODE *BadModes + ) +; + +/** + Returns the information about the optimum modes for the specified IDE device. + + This function is used by the driver entity to obtain the optimum ATA modes for + a specific device. The IDE controller driver takes into account the following + while calculating the mode: + - The IdentifyData inputs to EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() + - The BadModes inputs to EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode() + + The driver entity is required to call EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() + for all the devices that belong to an enumeration group before calling + EFI_IDE_CONTROLLER_INIT_PROTOCOL.CalculateMode() for any device in the same group. + + The IDE controller driver will use controller- and possibly platform-specific + algorithms to arrive at SupportedModes. The IDE controller may base its + decision on user preferences and other considerations as well. This function + may be called multiple times because the driver entity may renegotiate the mode + with the IDE controller driver using EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode(). + + The driver entity may collect timing information for various devices in any + order. The driver entity is responsible for making sure that all the dependencies + are satisfied. For example, the SupportedModes information for device A that + was previously returned may become stale after a call to + EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyMode() for device B. + + The buffer SupportedModes is allocated by the callee because the caller does + not necessarily know the size of the buffer. The type EFI_ATA_COLLECTIVE_MODE + is defined in a way that allows for future extensibility and can be of variable + length. This memory pool should be deallocated by the caller when it is no + longer necessary. + + The IDE controller driver for a Serial ATA (SATA) controller can use this + member function to force a lower speed (first-generation [Gen1] speeds on a + second-generation [Gen2]-capable hardware). The IDE controller driver can + also allow the driver entity to stay with the speed that has been negotiated + by the physical layer. + + @param[in] This The pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Channel A zero-based channel number. + @param[in] Device A zero-based device number on the Channel. + @param[out] SupportedModes The optimum modes for the device. + + @retval EFI_SUCCESS SupportedModes was returned. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + @retval EFI_INVALID_PARAMETER Device is invalid. + @retval EFI_INVALID_PARAMETER SupportedModes is NULL. + @retval EFI_NOT_READY Modes cannot be calculated due to a lack of + data. This error may happen if + EFI_IDE_CONTROLLER_INIT_PROTOCOL.SubmitData() + and EFI_IDE_CONTROLLER_INIT_PROTOCOL.DisqualifyData() + were not called for at least one drive in the + same enumeration group. + +**/ +EFI_STATUS +EFIAPI +IdeInitCalculateMode ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN UINT8 Channel, + IN UINT8 Device, + OUT EFI_ATA_COLLECTIVE_MODE **SupportedModes + ) +; + +/** + Commands the IDE controller driver to program the IDE controller hardware + so that the specified device can operate at the specified mode. + + This function is used by the driver entity to instruct the IDE controller + driver to program the IDE controller hardware to the specified modes. This + function can be called only once for a particular device. For a Serial ATA + (SATA) Advanced Host Controller Interface (AHCI) controller, no controller- + specific programming may be required. + + @param[in] This Pointer to the EFI_IDE_CONTROLLER_INIT_PROTOCOL instance. + @param[in] Channel Zero-based channel number. + @param[in] Device Zero-based device number on the Channel. + @param[in] Modes The modes to set. + + @retval EFI_SUCCESS The command was accepted without any errors. + @retval EFI_INVALID_PARAMETER Channel is invalid (Channel >= ChannelCount). + @retval EFI_INVALID_PARAMETER Device is invalid. + @retval EFI_NOT_READY Modes cannot be set at this time due to lack of data. + @retval EFI_DEVICE_ERROR Modes cannot be set due to hardware failure. + The driver entity should not use this device. + +**/ +EFI_STATUS +EFIAPI +IdeInitSetTiming ( + IN EFI_IDE_CONTROLLER_INIT_PROTOCOL *This, + IN UINT8 Channel, + IN UINT8 Device, + IN EFI_ATA_COLLECTIVE_MODE *Modes + ) +; + +// +// Forward reference declaration +// +/** + Retrieves a Unicode string that is the user readable name of the UEFI Driver. + + @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + @param Language A pointer to a three character ISO 639-2 language identifier. + This is the language of the driver name that that the caller + is requesting, and it must match one of the languages specified + in SupportedLanguages. The number of languages supported by a + driver is up to the driver writer. + @param DriverName A pointer to the Unicode string to return. This Unicode string + is the name of the driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER DriverName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This does not support the + language specified by Language. +**/ +EFI_STATUS +EFIAPI +SataControllerComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +; + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an UEFI Driver. + + @param This A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + @param ControllerHandle The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + @param OPTIONAL ChildHandle The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + @param Language A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + @param ControllerName A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language + specified by Language from the point of view of the + driver specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + @retval EFI_UNSUPPORTED The driver specified by This does not support the + language specified by Language. +**/ +EFI_STATUS +EFIAPI +SataControllerComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +; + +#endif diff --git a/CorebootModulePkg/SataControllerDxe/SataControllerDxe.inf b/CorebootModulePkg/SataControllerDxe/SataControllerDxe.inf new file mode 100644 index 0000000000..b0ed2f4db5 --- /dev/null +++ b/CorebootModulePkg/SataControllerDxe/SataControllerDxe.inf @@ -0,0 +1,49 @@ +## @file +# +# Component description file for the Sata Controller driver. +# +# Copyright (c) 2011, 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. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SataController + FILE_GUID = 8F4CD826-A5A0-4e93-9522-CFB0AB72926C + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeSataControllerDriver + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + ComponentName.c + SataController.c + SataController.h + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + DebugLib + UefiLib + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + +[Protocols] + gEfiPciIoProtocolGuid + gEfiIdeControllerInitProtocolGuid |