mirror of
https://github.com/acidanthera/audk.git
synced 2025-07-25 14:44:28 +02:00
MdeModulePkg/PciHostBridge: Count the (mm)io overhead when polling
RootBridgeIo.PollMem()/PollIo() originally don't count the IO/MMIO access overhead when delaying. The patch changes the implementation to count the access overhead so that the actually delay equals to user required delay. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com> Reviewed-by: Star Zeng <star.zeng@intel.com> Cc: Chasel Chiu <chasel.chiu@intel.com>
This commit is contained in:
parent
b22a62be5c
commit
0edb7ec5ce
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Provides the basic interfaces to abstract a PCI Host Bridge Resource Allocation.
|
Provides the basic interfaces to abstract a PCI Host Bridge Resource Allocation.
|
||||||
|
|
||||||
Copyright (c) 1999 - 2017, Intel Corporation. All rights reserved.<BR>
|
Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||||
This program and the accompanying materials
|
This program and the accompanying materials
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
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
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
@ -17,8 +17,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||||||
#include "PciRootBridge.h"
|
#include "PciRootBridge.h"
|
||||||
#include "PciHostResource.h"
|
#include "PciHostResource.h"
|
||||||
|
|
||||||
|
|
||||||
EFI_METRONOME_ARCH_PROTOCOL *mMetronome;
|
|
||||||
EFI_CPU_IO2_PROTOCOL *mCpuIo;
|
EFI_CPU_IO2_PROTOCOL *mCpuIo;
|
||||||
|
|
||||||
GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mAcpiAddressSpaceTypeStr[] = {
|
GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mAcpiAddressSpaceTypeStr[] = {
|
||||||
@ -406,8 +404,6 @@ InitializePciHostBridge (
|
|||||||
return EFI_UNSUPPORTED;
|
return EFI_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
Status = gBS->LocateProtocol (&gEfiMetronomeArchProtocolGuid, NULL, (VOID **) &mMetronome);
|
|
||||||
ASSERT_EFI_ERROR (Status);
|
|
||||||
Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **) &mCpuIo);
|
Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **) &mCpuIo);
|
||||||
ASSERT_EFI_ERROR (Status);
|
ASSERT_EFI_ERROR (Status);
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
The Header file of the Pci Host Bridge Driver.
|
The Header file of the Pci Host Bridge Driver.
|
||||||
|
|
||||||
Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.<BR>
|
Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||||
This program and the accompanying materials
|
This program and the accompanying materials
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
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
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
@ -268,6 +268,5 @@ GetTranslationByResourceType (
|
|||||||
IN PCI_RESOURCE_TYPE ResourceType
|
IN PCI_RESOURCE_TYPE ResourceType
|
||||||
);
|
);
|
||||||
|
|
||||||
extern EFI_METRONOME_ARCH_PROTOCOL *mMetronome;
|
|
||||||
extern EFI_CPU_IO2_PROTOCOL *mCpuIo;
|
extern EFI_CPU_IO2_PROTOCOL *mCpuIo;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
## @file
|
## @file
|
||||||
# Generic PCI Host Bridge driver.
|
# Generic PCI Host Bridge driver.
|
||||||
#
|
#
|
||||||
# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
|
# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||||
#
|
#
|
||||||
# This program and the accompanying materials
|
# This program and the accompanying materials
|
||||||
# are licensed and made available under the terms and conditions of the BSD License
|
# are licensed and made available under the terms and conditions of the BSD License
|
||||||
@ -43,9 +43,9 @@
|
|||||||
PciSegmentLib
|
PciSegmentLib
|
||||||
UefiLib
|
UefiLib
|
||||||
PciHostBridgeLib
|
PciHostBridgeLib
|
||||||
|
TimerLib
|
||||||
|
|
||||||
[Protocols]
|
[Protocols]
|
||||||
gEfiMetronomeArchProtocolGuid ## CONSUMES
|
|
||||||
gEfiCpuIo2ProtocolGuid ## CONSUMES
|
gEfiCpuIo2ProtocolGuid ## CONSUMES
|
||||||
gEfiDevicePathProtocolGuid ## BY_START
|
gEfiDevicePathProtocolGuid ## BY_START
|
||||||
gEfiPciRootBridgeIoProtocolGuid ## BY_START
|
gEfiPciRootBridgeIoProtocolGuid ## BY_START
|
||||||
@ -54,5 +54,4 @@
|
|||||||
|
|
||||||
[Depex]
|
[Depex]
|
||||||
gEfiCpuIo2ProtocolGuid AND
|
gEfiCpuIo2ProtocolGuid AND
|
||||||
gEfiMetronomeArchProtocolGuid AND
|
|
||||||
gEfiCpuArchProtocolGuid
|
gEfiCpuArchProtocolGuid
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
The PCI Root Bridge header file.
|
The PCI Root Bridge header file.
|
||||||
|
|
||||||
Copyright (c) 1999 - 2017, Intel Corporation. All rights reserved.<BR>
|
Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||||
This program and the accompanying materials
|
This program and the accompanying materials
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
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
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
@ -23,7 +23,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||||||
//
|
//
|
||||||
// Driver Consumed Protocol Prototypes
|
// Driver Consumed Protocol Prototypes
|
||||||
//
|
//
|
||||||
#include <Protocol/Metronome.h>
|
|
||||||
#include <Protocol/CpuIo2.h>
|
#include <Protocol/CpuIo2.h>
|
||||||
#include <Protocol/DevicePath.h>
|
#include <Protocol/DevicePath.h>
|
||||||
#include <Protocol/PciRootBridgeIo.h>
|
#include <Protocol/PciRootBridgeIo.h>
|
||||||
@ -36,6 +35,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||||||
#include <Library/BaseLib.h>
|
#include <Library/BaseLib.h>
|
||||||
#include <Library/PciSegmentLib.h>
|
#include <Library/PciSegmentLib.h>
|
||||||
#include <Library/UefiLib.h>
|
#include <Library/UefiLib.h>
|
||||||
|
#include <Library/TimerLib.h>
|
||||||
#include "PciHostResource.h"
|
#include "PciHostResource.h"
|
||||||
|
|
||||||
|
|
||||||
@ -574,7 +574,5 @@ RootBridgeIoConfiguration (
|
|||||||
)
|
)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
extern EFI_METRONOME_ARCH_PROTOCOL *mMetronome;
|
|
||||||
extern EFI_CPU_IO2_PROTOCOL *mCpuIo;
|
extern EFI_CPU_IO2_PROTOCOL *mCpuIo;
|
||||||
#endif
|
#endif
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
PCI Root Bridge Io Protocol code.
|
PCI Root Bridge Io Protocol code.
|
||||||
|
|
||||||
Copyright (c) 1999 - 2017, Intel Corporation. All rights reserved.<BR>
|
Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||||
This program and the accompanying materials
|
This program and the accompanying materials
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
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
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
@ -468,6 +468,85 @@ RootBridgeIoGetMemTranslationByAddress (
|
|||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return the result of (Multiplicand * Multiplier / Divisor).
|
||||||
|
|
||||||
|
@param Multiplicand A 64-bit unsigned value.
|
||||||
|
@param Multiplier A 64-bit unsigned value.
|
||||||
|
@param Divisor A 32-bit unsigned value.
|
||||||
|
@param Remainder A pointer to a 32-bit unsigned value. This parameter is
|
||||||
|
optional and may be NULL.
|
||||||
|
|
||||||
|
@return Multiplicand * Multiplier / Divisor.
|
||||||
|
**/
|
||||||
|
UINT64
|
||||||
|
MultThenDivU64x64x32 (
|
||||||
|
IN UINT64 Multiplicand,
|
||||||
|
IN UINT64 Multiplier,
|
||||||
|
IN UINT32 Divisor,
|
||||||
|
OUT UINT32 *Remainder OPTIONAL
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UINT64 Uint64;
|
||||||
|
UINT32 LocalRemainder;
|
||||||
|
UINT32 Uint32;
|
||||||
|
if (Multiplicand > DivU64x64Remainder (MAX_UINT64, Multiplier, NULL)) {
|
||||||
|
//
|
||||||
|
// Make sure Multiplicand is the bigger one.
|
||||||
|
//
|
||||||
|
if (Multiplicand < Multiplier) {
|
||||||
|
Uint64 = Multiplicand;
|
||||||
|
Multiplicand = Multiplier;
|
||||||
|
Multiplier = Uint64;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Because Multiplicand * Multiplier overflows,
|
||||||
|
// Multiplicand * Multiplier / Divisor
|
||||||
|
// = (2 * Multiplicand' + 1) * Multiplier / Divisor
|
||||||
|
// = 2 * (Multiplicand' * Multiplier / Divisor) + Multiplier / Divisor
|
||||||
|
//
|
||||||
|
Uint64 = MultThenDivU64x64x32 (RShiftU64 (Multiplicand, 1), Multiplier, Divisor, &LocalRemainder);
|
||||||
|
Uint64 = LShiftU64 (Uint64, 1);
|
||||||
|
Uint32 = 0;
|
||||||
|
if ((Multiplicand & 0x1) == 1) {
|
||||||
|
Uint64 += DivU64x32Remainder (Multiplier, Divisor, &Uint32);
|
||||||
|
}
|
||||||
|
return Uint64 + DivU64x32Remainder (Uint32 + LShiftU64 (LocalRemainder, 1), Divisor, Remainder);
|
||||||
|
} else {
|
||||||
|
return DivU64x32Remainder (MultU64x64 (Multiplicand, Multiplier), Divisor, Remainder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return the elapsed tick count from CurrentTick.
|
||||||
|
|
||||||
|
@param CurrentTick On input, the previous tick count.
|
||||||
|
On output, the current tick count.
|
||||||
|
@param StartTick The value the performance counter starts with when it
|
||||||
|
rolls over.
|
||||||
|
@param EndTick The value that the performance counter ends with before
|
||||||
|
it rolls over.
|
||||||
|
|
||||||
|
@return The elapsed tick count from CurrentTick.
|
||||||
|
**/
|
||||||
|
UINT64
|
||||||
|
GetElapsedTick (
|
||||||
|
UINT64 *CurrentTick,
|
||||||
|
UINT64 StartTick,
|
||||||
|
UINT64 EndTick
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UINT64 PreviousTick;
|
||||||
|
|
||||||
|
PreviousTick = *CurrentTick;
|
||||||
|
*CurrentTick = GetPerformanceCounter();
|
||||||
|
if (StartTick < EndTick) {
|
||||||
|
return *CurrentTick - PreviousTick;
|
||||||
|
} else {
|
||||||
|
return PreviousTick - *CurrentTick;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Polls an address in memory mapped I/O space until an exit condition is met,
|
Polls an address in memory mapped I/O space until an exit condition is met,
|
||||||
or a timeout occurs.
|
or a timeout occurs.
|
||||||
@ -517,6 +596,11 @@ RootBridgeIoPollMem (
|
|||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
UINT64 NumberOfTicks;
|
UINT64 NumberOfTicks;
|
||||||
UINT32 Remainder;
|
UINT32 Remainder;
|
||||||
|
UINT64 StartTick;
|
||||||
|
UINT64 EndTick;
|
||||||
|
UINT64 CurrentTick;
|
||||||
|
UINT64 ElapsedTick;
|
||||||
|
UINT64 Frequency;
|
||||||
|
|
||||||
if (Result == NULL) {
|
if (Result == NULL) {
|
||||||
return EFI_INVALID_PARAMETER;
|
return EFI_INVALID_PARAMETER;
|
||||||
@ -542,28 +626,18 @@ RootBridgeIoPollMem (
|
|||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Determine the proper # of metronome ticks to wait for polling the
|
// NumberOfTicks = Frenquency * Delay / EFI_TIMER_PERIOD_SECONDS(1)
|
||||||
// location. The nuber of ticks is Roundup (Delay /
|
|
||||||
// mMetronome->TickPeriod)+1
|
|
||||||
// The "+1" to account for the possibility of the first tick being short
|
|
||||||
// because we started in the middle of a tick.
|
|
||||||
//
|
//
|
||||||
// BugBug: overriding mMetronome->TickPeriod with UINT32 until Metronome
|
Frequency = GetPerformanceCounterProperties (&StartTick, &EndTick);
|
||||||
// protocol definition is updated.
|
NumberOfTicks = MultThenDivU64x64x32 (Frequency, Delay, (UINT32)EFI_TIMER_PERIOD_SECONDS(1), &Remainder);
|
||||||
//
|
if (Remainder >= (UINTN)EFI_TIMER_PERIOD_SECONDS(1) / 2) {
|
||||||
NumberOfTicks = DivU64x32Remainder (Delay, (UINT32) mMetronome->TickPeriod,
|
NumberOfTicks++;
|
||||||
&Remainder);
|
|
||||||
if (Remainder != 0) {
|
|
||||||
NumberOfTicks += 1;
|
|
||||||
}
|
}
|
||||||
NumberOfTicks += 1;
|
for ( ElapsedTick = 0, CurrentTick = GetPerformanceCounter()
|
||||||
|
; ElapsedTick <= NumberOfTicks
|
||||||
while (NumberOfTicks != 0) {
|
; ElapsedTick += GetElapsedTick (&CurrentTick, StartTick, EndTick)
|
||||||
|
) {
|
||||||
mMetronome->WaitForTick (mMetronome, 1);
|
|
||||||
|
|
||||||
Status = This->Mem.Read (This, Width, Address, 1, Result);
|
Status = This->Mem.Read (This, Width, Address, 1, Result);
|
||||||
if (EFI_ERROR (Status)) {
|
if (EFI_ERROR (Status)) {
|
||||||
return Status;
|
return Status;
|
||||||
@ -572,8 +646,6 @@ RootBridgeIoPollMem (
|
|||||||
if ((*Result & Mask) == Value) {
|
if ((*Result & Mask) == Value) {
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
NumberOfTicks -= 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return EFI_TIMEOUT;
|
return EFI_TIMEOUT;
|
||||||
@ -626,6 +698,11 @@ RootBridgeIoPollIo (
|
|||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
UINT64 NumberOfTicks;
|
UINT64 NumberOfTicks;
|
||||||
UINT32 Remainder;
|
UINT32 Remainder;
|
||||||
|
UINT64 StartTick;
|
||||||
|
UINT64 EndTick;
|
||||||
|
UINT64 CurrentTick;
|
||||||
|
UINT64 ElapsedTick;
|
||||||
|
UINT64 Frequency;
|
||||||
|
|
||||||
//
|
//
|
||||||
// No matter what, always do a single poll.
|
// No matter what, always do a single poll.
|
||||||
@ -651,25 +728,18 @@ RootBridgeIoPollIo (
|
|||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Determine the proper # of metronome ticks to wait for polling the
|
// NumberOfTicks = Frenquency * Delay / EFI_TIMER_PERIOD_SECONDS(1)
|
||||||
// location. The number of ticks is Roundup (Delay /
|
|
||||||
// mMetronome->TickPeriod)+1
|
|
||||||
// The "+1" to account for the possibility of the first tick being short
|
|
||||||
// because we started in the middle of a tick.
|
|
||||||
//
|
//
|
||||||
NumberOfTicks = DivU64x32Remainder (Delay, (UINT32)mMetronome->TickPeriod,
|
Frequency = GetPerformanceCounterProperties (&StartTick, &EndTick);
|
||||||
&Remainder);
|
NumberOfTicks = MultThenDivU64x64x32 (Frequency, Delay, (UINT32)EFI_TIMER_PERIOD_SECONDS(1), &Remainder);
|
||||||
if (Remainder != 0) {
|
if (Remainder >= (UINTN)EFI_TIMER_PERIOD_SECONDS(1) / 2) {
|
||||||
NumberOfTicks += 1;
|
NumberOfTicks++;
|
||||||
}
|
}
|
||||||
NumberOfTicks += 1;
|
for ( ElapsedTick = 0, CurrentTick = GetPerformanceCounter()
|
||||||
|
; ElapsedTick <= NumberOfTicks
|
||||||
while (NumberOfTicks != 0) {
|
; ElapsedTick += GetElapsedTick (&CurrentTick, StartTick, EndTick)
|
||||||
|
) {
|
||||||
mMetronome->WaitForTick (mMetronome, 1);
|
|
||||||
|
|
||||||
Status = This->Io.Read (This, Width, Address, 1, Result);
|
Status = This->Io.Read (This, Width, Address, 1, Result);
|
||||||
if (EFI_ERROR (Status)) {
|
if (EFI_ERROR (Status)) {
|
||||||
return Status;
|
return Status;
|
||||||
@ -678,8 +748,6 @@ RootBridgeIoPollIo (
|
|||||||
if ((*Result & Mask) == Value) {
|
if ((*Result & Mask) == Value) {
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
NumberOfTicks -= 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return EFI_TIMEOUT;
|
return EFI_TIMEOUT;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user