mirror of https://github.com/acidanthera/audk.git
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.
|
||||
|
||||
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
|
||||
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
|
||||
|
@ -17,8 +17,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||
#include "PciRootBridge.h"
|
||||
#include "PciHostResource.h"
|
||||
|
||||
|
||||
EFI_METRONOME_ARCH_PROTOCOL *mMetronome;
|
||||
EFI_CPU_IO2_PROTOCOL *mCpuIo;
|
||||
|
||||
GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mAcpiAddressSpaceTypeStr[] = {
|
||||
|
@ -406,8 +404,6 @@ InitializePciHostBridge (
|
|||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
Status = gBS->LocateProtocol (&gEfiMetronomeArchProtocolGuid, NULL, (VOID **) &mMetronome);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **) &mCpuIo);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
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
|
||||
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
|
||||
|
@ -268,6 +268,5 @@ GetTranslationByResourceType (
|
|||
IN PCI_RESOURCE_TYPE ResourceType
|
||||
);
|
||||
|
||||
extern EFI_METRONOME_ARCH_PROTOCOL *mMetronome;
|
||||
extern EFI_CPU_IO2_PROTOCOL *mCpuIo;
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
## @file
|
||||
# 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
|
||||
# are licensed and made available under the terms and conditions of the BSD License
|
||||
|
@ -43,9 +43,9 @@
|
|||
PciSegmentLib
|
||||
UefiLib
|
||||
PciHostBridgeLib
|
||||
TimerLib
|
||||
|
||||
[Protocols]
|
||||
gEfiMetronomeArchProtocolGuid ## CONSUMES
|
||||
gEfiCpuIo2ProtocolGuid ## CONSUMES
|
||||
gEfiDevicePathProtocolGuid ## BY_START
|
||||
gEfiPciRootBridgeIoProtocolGuid ## BY_START
|
||||
|
@ -54,5 +54,4 @@
|
|||
|
||||
[Depex]
|
||||
gEfiCpuIo2ProtocolGuid AND
|
||||
gEfiMetronomeArchProtocolGuid AND
|
||||
gEfiCpuArchProtocolGuid
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
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
|
||||
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
|
||||
|
@ -23,7 +23,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||
//
|
||||
// Driver Consumed Protocol Prototypes
|
||||
//
|
||||
#include <Protocol/Metronome.h>
|
||||
#include <Protocol/CpuIo2.h>
|
||||
#include <Protocol/DevicePath.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/PciSegmentLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/TimerLib.h>
|
||||
#include "PciHostResource.h"
|
||||
|
||||
|
||||
|
@ -574,7 +574,5 @@ RootBridgeIoConfiguration (
|
|||
)
|
||||
;
|
||||
|
||||
|
||||
extern EFI_METRONOME_ARCH_PROTOCOL *mMetronome;
|
||||
extern EFI_CPU_IO2_PROTOCOL *mCpuIo;
|
||||
#endif
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
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
|
||||
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
|
||||
|
@ -468,6 +468,85 @@ RootBridgeIoGetMemTranslationByAddress (
|
|||
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,
|
||||
or a timeout occurs.
|
||||
|
@ -517,6 +596,11 @@ RootBridgeIoPollMem (
|
|||
EFI_STATUS Status;
|
||||
UINT64 NumberOfTicks;
|
||||
UINT32 Remainder;
|
||||
UINT64 StartTick;
|
||||
UINT64 EndTick;
|
||||
UINT64 CurrentTick;
|
||||
UINT64 ElapsedTick;
|
||||
UINT64 Frequency;
|
||||
|
||||
if (Result == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
@ -542,28 +626,18 @@ RootBridgeIoPollMem (
|
|||
return EFI_SUCCESS;
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// Determine the proper # of metronome ticks to wait for polling the
|
||||
// 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.
|
||||
// NumberOfTicks = Frenquency * Delay / EFI_TIMER_PERIOD_SECONDS(1)
|
||||
//
|
||||
// BugBug: overriding mMetronome->TickPeriod with UINT32 until Metronome
|
||||
// protocol definition is updated.
|
||||
//
|
||||
NumberOfTicks = DivU64x32Remainder (Delay, (UINT32) mMetronome->TickPeriod,
|
||||
&Remainder);
|
||||
if (Remainder != 0) {
|
||||
NumberOfTicks += 1;
|
||||
Frequency = GetPerformanceCounterProperties (&StartTick, &EndTick);
|
||||
NumberOfTicks = MultThenDivU64x64x32 (Frequency, Delay, (UINT32)EFI_TIMER_PERIOD_SECONDS(1), &Remainder);
|
||||
if (Remainder >= (UINTN)EFI_TIMER_PERIOD_SECONDS(1) / 2) {
|
||||
NumberOfTicks++;
|
||||
}
|
||||
NumberOfTicks += 1;
|
||||
|
||||
while (NumberOfTicks != 0) {
|
||||
|
||||
mMetronome->WaitForTick (mMetronome, 1);
|
||||
|
||||
for ( ElapsedTick = 0, CurrentTick = GetPerformanceCounter()
|
||||
; ElapsedTick <= NumberOfTicks
|
||||
; ElapsedTick += GetElapsedTick (&CurrentTick, StartTick, EndTick)
|
||||
) {
|
||||
Status = This->Mem.Read (This, Width, Address, 1, Result);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
|
@ -572,8 +646,6 @@ RootBridgeIoPollMem (
|
|||
if ((*Result & Mask) == Value) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
NumberOfTicks -= 1;
|
||||
}
|
||||
}
|
||||
return EFI_TIMEOUT;
|
||||
|
@ -626,6 +698,11 @@ RootBridgeIoPollIo (
|
|||
EFI_STATUS Status;
|
||||
UINT64 NumberOfTicks;
|
||||
UINT32 Remainder;
|
||||
UINT64 StartTick;
|
||||
UINT64 EndTick;
|
||||
UINT64 CurrentTick;
|
||||
UINT64 ElapsedTick;
|
||||
UINT64 Frequency;
|
||||
|
||||
//
|
||||
// No matter what, always do a single poll.
|
||||
|
@ -651,25 +728,18 @@ RootBridgeIoPollIo (
|
|||
return EFI_SUCCESS;
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// Determine the proper # of metronome ticks to wait for polling the
|
||||
// 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 = Frenquency * Delay / EFI_TIMER_PERIOD_SECONDS(1)
|
||||
//
|
||||
NumberOfTicks = DivU64x32Remainder (Delay, (UINT32)mMetronome->TickPeriod,
|
||||
&Remainder);
|
||||
if (Remainder != 0) {
|
||||
NumberOfTicks += 1;
|
||||
Frequency = GetPerformanceCounterProperties (&StartTick, &EndTick);
|
||||
NumberOfTicks = MultThenDivU64x64x32 (Frequency, Delay, (UINT32)EFI_TIMER_PERIOD_SECONDS(1), &Remainder);
|
||||
if (Remainder >= (UINTN)EFI_TIMER_PERIOD_SECONDS(1) / 2) {
|
||||
NumberOfTicks++;
|
||||
}
|
||||
NumberOfTicks += 1;
|
||||
|
||||
while (NumberOfTicks != 0) {
|
||||
|
||||
mMetronome->WaitForTick (mMetronome, 1);
|
||||
|
||||
for ( ElapsedTick = 0, CurrentTick = GetPerformanceCounter()
|
||||
; ElapsedTick <= NumberOfTicks
|
||||
; ElapsedTick += GetElapsedTick (&CurrentTick, StartTick, EndTick)
|
||||
) {
|
||||
Status = This->Io.Read (This, Width, Address, 1, Result);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
|
@ -678,8 +748,6 @@ RootBridgeIoPollIo (
|
|||
if ((*Result & Mask) == Value) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
NumberOfTicks -= 1;
|
||||
}
|
||||
}
|
||||
return EFI_TIMEOUT;
|
||||
|
|
Loading…
Reference in New Issue