summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Bus/Pci/PciHostBridgeDxe
diff options
context:
space:
mode:
authorRuiyu Ni <ruiyu.ni@intel.com>2018-04-23 14:20:26 +0800
committerRuiyu Ni <ruiyu.ni@intel.com>2018-05-09 14:03:09 +0800
commit0edb7ec5ced0a28b93bf8c13b12f0a277c44dbbc (patch)
tree091cdf7c1c1df4b6889b9e0582d53c10ba71603f /MdeModulePkg/Bus/Pci/PciHostBridgeDxe
parentb22a62be5cdc8fd19d87ec1ecfa5b28fb9be50ad (diff)
downloadedk2-0edb7ec5ced0a28b93bf8c13b12f0a277c44dbbc.zip
edk2-0edb7ec5ced0a28b93bf8c13b12f0a277c44dbbc.tar.gz
edk2-0edb7ec5ced0a28b93bf8c13b12f0a277c44dbbc.tar.bz2
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>
Diffstat (limited to 'MdeModulePkg/Bus/Pci/PciHostBridgeDxe')
-rw-r--r--MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c6
-rw-r--r--MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.h3
-rw-r--r--MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf5
-rw-r--r--MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h6
-rw-r--r--MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c148
5 files changed, 114 insertions, 54 deletions
diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
index 8b71363..0c1f75e 100644
--- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
+++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
@@ -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);
diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.h b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.h
index c2791ea..bc9c721 100644
--- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.h
+++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.h
@@ -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
diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
index 42bd8a2..2dd4efb 100644
--- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
+++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
@@ -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
diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h
index d3dfb57..0687105 100644
--- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h
+++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h
@@ -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
diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c
index 5764c2f..83f553a 100644
--- a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c
+++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c
@@ -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
@@ -469,6 +469,85 @@ RootBridgeIoGetMemTranslationByAddress (
}
/**
+ 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.
//
- // BugBug: overriding mMetronome->TickPeriod with UINT32 until Metronome
- // protocol definition is updated.
+ // 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->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;