MdeModulePkg/Bus/Pci/PciBusDxe: Support PCIe Resizable BAR Capability

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=313

Add PcdPcieResizableBarSupport to enable/disable PCIe Resizable
BAR Capability fearture.
Program the Resizable BAR Register if the device suports PCIe Resizable
BAR Capability and PcdPcieResizableBarSupport is TRUE.

Cc: Ray Ni <ray.ni@intel.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Signed-off-by: Heng Luo <heng.luo@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
This commit is contained in:
Luo, Heng
2021-01-04 14:59:54 +08:00
committed by mergify[bot]
parent 42fe8ca453
commit 0785c619a5
7 changed files with 241 additions and 20 deletions

View File

@@ -1,7 +1,7 @@
/** @file
Internal library implementation for PCI Bus module.
Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -377,6 +377,60 @@ DumpResourceMap (
}
}
/**
Adjust the Devices' BAR size to minimum value if it support Resizeable BAR capability.
@param RootBridgeDev Pointer to instance of PCI_IO_DEVICE..
@return TRUE if BAR size is adjusted.
**/
BOOLEAN
AdjustPciDeviceBarSize (
IN PCI_IO_DEVICE *RootBridgeDev
)
{
PCI_IO_DEVICE *PciIoDevice;
LIST_ENTRY *CurrentLink;
BOOLEAN Adjusted;
UINTN Offset;
UINTN BarIndex;
Adjusted = FALSE;
CurrentLink = RootBridgeDev->ChildList.ForwardLink;
while (CurrentLink != NULL && CurrentLink != &RootBridgeDev->ChildList) {
PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
if (AdjustPciDeviceBarSize (PciIoDevice)) {
Adjusted = TRUE;
}
} else {
if (PciIoDevice->ResizableBarOffset != 0) {
DEBUG ((
DEBUG_ERROR,
"PciBus: [%02x|%02x|%02x] Adjust Pci Device Bar Size\n",
PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber
));
PciProgramResizableBar (PciIoDevice, PciResizableBarMin);
//
// Start to parse the bars
//
for (Offset = 0x10, BarIndex = 0; Offset <= 0x24 && BarIndex < PCI_MAX_BAR; BarIndex++) {
Offset = PciParseBar (PciIoDevice, Offset, BarIndex);
}
Adjusted = TRUE;
DEBUG_CODE (DumpPciBars (PciIoDevice););
}
}
CurrentLink = CurrentLink->ForwardLink;
}
return Adjusted;
}
/**
Submits the I/O and memory resource requirements for the specified PCI Host Bridge.
@@ -422,6 +476,10 @@ PciHostBridgeResourceAllocator (
PCI_RESOURCE_NODE PMem64Pool;
EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD HandleExtendedData;
EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD AllocFailExtendedData;
BOOLEAN ResizableBarNeedAdjust;
BOOLEAN ResizableBarAdjusted;
ResizableBarNeedAdjust = PcdGetBool (PcdPcieResizableBarSupport);
//
// It may try several times if the resource allocation fails
@@ -703,19 +761,30 @@ PciHostBridgeResourceAllocator (
sizeof (AllocFailExtendedData)
);
Status = PciHostBridgeAdjustAllocation (
&IoPool,
&Mem32Pool,
&PMem32Pool,
&Mem64Pool,
&PMem64Pool,
IoResStatus,
Mem32ResStatus,
PMem32ResStatus,
Mem64ResStatus,
PMem64ResStatus
);
//
// When resource conflict happens, adjust the BAR size first.
// Only when adjusting BAR size doesn't help or BAR size cannot be adjusted,
// reject the device who requests largest resource that causes conflict.
//
ResizableBarAdjusted = FALSE;
if (ResizableBarNeedAdjust) {
ResizableBarAdjusted = AdjustPciDeviceBarSize (RootBridgeDev);
ResizableBarNeedAdjust = FALSE;
}
if (!ResizableBarAdjusted) {
Status = PciHostBridgeAdjustAllocation (
&IoPool,
&Mem32Pool,
&PMem32Pool,
&Mem64Pool,
&PMem64Pool,
IoResStatus,
Mem32ResStatus,
PMem32ResStatus,
Mem64ResStatus,
PMem64ResStatus
);
}
//
// Destroy all the resource tree
//
@@ -1651,3 +1720,91 @@ PciHostBridgeEnumerator (
return EFI_SUCCESS;
}
/**
This function is used to program the Resizable BAR Register.
@param PciIoDevice A pointer to the PCI_IO_DEVICE.
@param ResizableBarOp PciResizableBarMax: Set BAR to max size
PciResizableBarMin: set BAR to min size.
@retval EFI_SUCCESS Successfully enumerated the host bridge.
@retval other Some error occurred when enumerating the host bridge.
**/
EFI_STATUS
PciProgramResizableBar (
IN PCI_IO_DEVICE *PciIoDevice,
IN PCI_RESIZABLE_BAR_OPERATION ResizableBarOp
)
{
EFI_PCI_IO_PROTOCOL *PciIo;
UINT64 Capabilities;
UINT32 Index;
UINT32 Offset;
INTN Bit;
UINTN ResizableBarNumber;
EFI_STATUS Status;
PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_ENTRY Entries[PCI_MAX_BAR];
ASSERT (PciIoDevice->ResizableBarOffset != 0);
DEBUG ((DEBUG_INFO, " Programs Resizable BAR register, offset: 0x%08x, number: %d\n",
PciIoDevice->ResizableBarOffset, PciIoDevice->ResizableBarNumber));
ResizableBarNumber = MIN (PciIoDevice->ResizableBarNumber, PCI_MAX_BAR);
PciIo = &PciIoDevice->PciIo;
Status = PciIo->Pci.Read (
PciIo,
EfiPciIoWidthUint8,
PciIoDevice->ResizableBarOffset + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER),
sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_ENTRY) * ResizableBarNumber,
(VOID *)(&Entries)
);
ASSERT_EFI_ERROR (Status);
for (Index = 0; Index < ResizableBarNumber; Index++) {
//
// When the bit of Capabilities Set, indicates that the Function supports
// operating with the BAR sized to (2^Bit) MB.
// Example:
// Bit 0 is set: supports operating with the BAR sized to 1 MB
// Bit 1 is set: supports operating with the BAR sized to 2 MB
// Bit n is set: supports operating with the BAR sized to (2^n) MB
//
Capabilities = LShiftU64(Entries[Index].ResizableBarControl.Bits.BarSizeCapability, 28)
| Entries[Index].ResizableBarCapability.Bits.BarSizeCapability;
if (ResizableBarOp == PciResizableBarMax) {
Bit = HighBitSet64(Capabilities);
} else if (ResizableBarOp == PciResizableBarMin) {
Bit = LowBitSet64(Capabilities);
} else {
ASSERT ((ResizableBarOp == PciResizableBarMax) || (ResizableBarOp == PciResizableBarMin));
}
ASSERT (Bit >= 0);
Offset = PciIoDevice->ResizableBarOffset + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER)
+ Index * sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_ENTRY)
+ OFFSET_OF (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_ENTRY, ResizableBarControl);
Entries[Index].ResizableBarControl.Bits.BarSize = (UINT32) Bit;
DEBUG ((
DEBUG_INFO,
" Resizable Bar: Offset = 0x%x, Bar Size Capability = 0x%016lx, New Bar Size = 0x%lx\n",
OFFSET_OF (PCI_TYPE00, Device.Bar[Entries[Index].ResizableBarControl.Bits.BarIndex]),
Capabilities, LShiftU64 (SIZE_1MB, Bit)
));
PciIo->Pci.Write (
PciIo,
EfiPciIoWidthUint32,
Offset,
1,
&Entries[Index].ResizableBarControl.Uint32
);
}
return EFI_SUCCESS;
}