\r
PCI Root Bridge Io Protocol code.\r
\r
-Copyright (c) 1999 - 2017, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include "PciRootBridge.h"\r
#include "PciHostResource.h"\r
\r
-extern EDKII_IOMMU_PROTOCOL *mIoMmuProtocol;\r
-\r
#define NO_MAPPING (VOID *) (UINTN) -1\r
\r
+#define RESOURCE_VALID(Resource) ((Resource)->Base <= (Resource)->Limit)\r
+\r
//\r
// Lookup table for increment values based on transfer widths\r
//\r
\r
DevicePathStr = NULL;\r
\r
- DEBUG ((EFI_D_INFO, "RootBridge: "));\r
- DEBUG ((EFI_D_INFO, "%s\n", DevicePathStr = ConvertDevicePathToText (Bridge->DevicePath, FALSE, FALSE)));\r
- DEBUG ((EFI_D_INFO, " Support/Attr: %lx / %lx\n", Bridge->Supports, Bridge->Attributes));\r
- DEBUG ((EFI_D_INFO, " DmaAbove4G: %s\n", Bridge->DmaAbove4G ? L"Yes" : L"No"));\r
- DEBUG ((EFI_D_INFO, "NoExtConfSpace: %s\n", Bridge->NoExtendedConfigSpace ? L"Yes" : L"No"));\r
- DEBUG ((EFI_D_INFO, " AllocAttr: %lx (%s%s)\n", Bridge->AllocationAttributes,\r
+ DEBUG ((DEBUG_INFO, "RootBridge: "));\r
+ DEBUG ((DEBUG_INFO, "%s\n", DevicePathStr = ConvertDevicePathToText (Bridge->DevicePath, FALSE, FALSE)));\r
+ DEBUG ((DEBUG_INFO, " Support/Attr: %lx / %lx\n", Bridge->Supports, Bridge->Attributes));\r
+ DEBUG ((DEBUG_INFO, " DmaAbove4G: %s\n", Bridge->DmaAbove4G ? L"Yes" : L"No"));\r
+ DEBUG ((DEBUG_INFO, "NoExtConfSpace: %s\n", Bridge->NoExtendedConfigSpace ? L"Yes" : L"No"));\r
+ DEBUG ((DEBUG_INFO, " AllocAttr: %lx (%s%s)\n", Bridge->AllocationAttributes,\r
(Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0 ? L"CombineMemPMem " : L"",\r
(Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) != 0 ? L"Mem64Decode" : L""\r
));\r
DEBUG ((\r
- EFI_D_INFO, " Bus: %lx - %lx Translation=%lx\n",\r
+ DEBUG_INFO, " Bus: %lx - %lx Translation=%lx\n",\r
Bridge->Bus.Base, Bridge->Bus.Limit, Bridge->Bus.Translation\r
));\r
//\r
//\r
// Make sure Mem and MemAbove4G apertures are valid\r
//\r
- if (Bridge->Mem.Base <= Bridge->Mem.Limit) {\r
+ if (RESOURCE_VALID (&Bridge->Mem)) {\r
ASSERT (Bridge->Mem.Limit < SIZE_4GB);\r
if (Bridge->Mem.Limit >= SIZE_4GB) {\r
return NULL;\r
}\r
}\r
- if (Bridge->MemAbove4G.Base <= Bridge->MemAbove4G.Limit) {\r
+ if (RESOURCE_VALID (&Bridge->MemAbove4G)) {\r
ASSERT (Bridge->MemAbove4G.Base >= SIZE_4GB);\r
if (Bridge->MemAbove4G.Base < SIZE_4GB) {\r
return NULL;\r
}\r
}\r
- if (Bridge->PMem.Base <= Bridge->PMem.Limit) {\r
+ if (RESOURCE_VALID (&Bridge->PMem)) {\r
ASSERT (Bridge->PMem.Limit < SIZE_4GB);\r
if (Bridge->PMem.Limit >= SIZE_4GB) {\r
return NULL;\r
}\r
}\r
- if (Bridge->PMemAbove4G.Base <= Bridge->PMemAbove4G.Limit) {\r
+ if (RESOURCE_VALID (&Bridge->PMemAbove4G)) {\r
ASSERT (Bridge->PMemAbove4G.Base >= SIZE_4GB);\r
if (Bridge->PMemAbove4G.Base < SIZE_4GB) {\r
return NULL;\r
// support separate windows for Non-prefetchable and Prefetchable\r
// memory.\r
//\r
- ASSERT (Bridge->PMem.Base > Bridge->PMem.Limit);\r
- ASSERT (Bridge->PMemAbove4G.Base > Bridge->PMemAbove4G.Limit);\r
- if ((Bridge->PMem.Base <= Bridge->PMem.Limit) ||\r
- (Bridge->PMemAbove4G.Base <= Bridge->PMemAbove4G.Limit)\r
- ) {\r
+ ASSERT (!RESOURCE_VALID (&Bridge->PMem));\r
+ ASSERT (!RESOURCE_VALID (&Bridge->PMemAbove4G));\r
+ if (RESOURCE_VALID (&Bridge->PMem) || RESOURCE_VALID (&Bridge->PMemAbove4G)) {\r
return NULL;\r
}\r
}\r
// If this bit is not set, then the PCI Root Bridge does not support\r
// 64 bit memory windows.\r
//\r
- ASSERT (Bridge->MemAbove4G.Base > Bridge->MemAbove4G.Limit);\r
- ASSERT (Bridge->PMemAbove4G.Base > Bridge->PMemAbove4G.Limit);\r
- if ((Bridge->MemAbove4G.Base <= Bridge->MemAbove4G.Limit) ||\r
- (Bridge->PMemAbove4G.Base <= Bridge->PMemAbove4G.Limit)\r
- ) {\r
+ ASSERT (!RESOURCE_VALID (&Bridge->MemAbove4G));\r
+ ASSERT (!RESOURCE_VALID (&Bridge->PMemAbove4G));\r
+ if (RESOURCE_VALID (&Bridge->MemAbove4G) || RESOURCE_VALID (&Bridge->PMemAbove4G)) {\r
return NULL;\r
}\r
}\r
\r
@retval EFI_INVALID_PARAMETER Buffer is NULL.\r
\r
+ @retval EFI_INVALID_PARAMETER Address or Count is invalid.\r
+\r
@retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.\r
\r
@retval EFI_UNSUPPORTED The address range specified by Address, Width,\r
UINT64 Base;\r
UINT64 Limit;\r
UINT32 Size;\r
+ UINT64 Length;\r
\r
//\r
// Check to see if Buffer is NULL\r
}\r
\r
//\r
- // For FIFO type, the target address won't increase during the access,\r
+ // For FIFO type, the device address won't increase during the access,\r
// so treat Count as 1\r
//\r
if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {\r
Width = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (Width & 0x03);\r
Size = 1 << Width;\r
\r
+ //\r
+ // Make sure (Count * Size) doesn't exceed MAX_UINT64\r
+ //\r
+ if (Count > DivU64x32 (MAX_UINT64, Size)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
//\r
// Check to see if Address is aligned\r
//\r
return EFI_UNSUPPORTED;\r
}\r
\r
+ //\r
+ // Make sure (Address + Count * Size) doesn't exceed MAX_UINT64\r
+ //\r
+ Length = MultU64x32 (Count, Size);\r
+ if (Address > MAX_UINT64 - Length) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
\r
//\r
//\r
// Allow Legacy IO access\r
//\r
- if (Address + MultU64x32 (Count, Size) <= 0x1000) {\r
+ if (Address + Length <= 0x1000) {\r
if ((RootBridge->Attributes & (\r
EFI_PCI_ATTRIBUTE_ISA_IO | EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_ATTRIBUTE_VGA_IO |\r
EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO |\r
//\r
// Allow Legacy MMIO access\r
//\r
- if ((Address >= 0xA0000) && (Address + MultU64x32 (Count, Size)) <= 0xC0000) {\r
+ if ((Address >= 0xA0000) && (Address + Length) <= 0xC0000) {\r
if ((RootBridge->Attributes & EFI_PCI_ATTRIBUTE_VGA_MEMORY) != 0) {\r
return EFI_SUCCESS;\r
}\r
// By comparing the Address against Limit we know which range to be used\r
// for checking\r
//\r
- if (Address + MultU64x32 (Count, Size) <= RootBridge->Mem.Limit + 1) {\r
- Base = RootBridge->Mem.Base;\r
+ if ((Address >= RootBridge->Mem.Base) && (Address + Length <= RootBridge->Mem.Limit + 1)) {\r
+ Base = RootBridge->Mem.Base;\r
Limit = RootBridge->Mem.Limit;\r
- } else {\r
- Base = RootBridge->MemAbove4G.Base;\r
+ } else if ((Address >= RootBridge->PMem.Base) && (Address + Length <= RootBridge->PMem.Limit + 1)) {\r
+ Base = RootBridge->PMem.Base;\r
+ Limit = RootBridge->PMem.Limit;\r
+ } else if ((Address >= RootBridge->MemAbove4G.Base) && (Address + Length <= RootBridge->MemAbove4G.Limit + 1)) {\r
+ Base = RootBridge->MemAbove4G.Base;\r
Limit = RootBridge->MemAbove4G.Limit;\r
+ } else {\r
+ Base = RootBridge->PMemAbove4G.Base;\r
+ Limit = RootBridge->PMemAbove4G.Limit;\r
}\r
} else {\r
PciRbAddr = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*) &Address;\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- if (Address + MultU64x32 (Count, Size) > Limit + 1) {\r
+ if (Address + Length > Limit + 1) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Return the result of (Multiplicand * Multiplier / Divisor).\r
+\r
+ @param Multiplicand A 64-bit unsigned value.\r
+ @param Multiplier A 64-bit unsigned value.\r
+ @param Divisor A 32-bit unsigned value.\r
+ @param Remainder A pointer to a 32-bit unsigned value. This parameter is\r
+ optional and may be NULL.\r
+\r
+ @return Multiplicand * Multiplier / Divisor.\r
+**/\r
+UINT64\r
+MultThenDivU64x64x32 (\r
+ IN UINT64 Multiplicand,\r
+ IN UINT64 Multiplier,\r
+ IN UINT32 Divisor,\r
+ OUT UINT32 *Remainder OPTIONAL\r
+ )\r
+{\r
+ UINT64 Uint64;\r
+ UINT32 LocalRemainder;\r
+ UINT32 Uint32;\r
+ if (Multiplicand > DivU64x64Remainder (MAX_UINT64, Multiplier, NULL)) {\r
+ //\r
+ // Make sure Multiplicand is the bigger one.\r
+ //\r
+ if (Multiplicand < Multiplier) {\r
+ Uint64 = Multiplicand;\r
+ Multiplicand = Multiplier;\r
+ Multiplier = Uint64;\r
+ }\r
+ //\r
+ // Because Multiplicand * Multiplier overflows,\r
+ // Multiplicand * Multiplier / Divisor\r
+ // = (2 * Multiplicand' + 1) * Multiplier / Divisor\r
+ // = 2 * (Multiplicand' * Multiplier / Divisor) + Multiplier / Divisor\r
+ //\r
+ Uint64 = MultThenDivU64x64x32 (RShiftU64 (Multiplicand, 1), Multiplier, Divisor, &LocalRemainder);\r
+ Uint64 = LShiftU64 (Uint64, 1);\r
+ Uint32 = 0;\r
+ if ((Multiplicand & 0x1) == 1) {\r
+ Uint64 += DivU64x32Remainder (Multiplier, Divisor, &Uint32);\r
+ }\r
+ return Uint64 + DivU64x32Remainder (Uint32 + LShiftU64 (LocalRemainder, 1), Divisor, Remainder);\r
+ } else {\r
+ return DivU64x32Remainder (MultU64x64 (Multiplicand, Multiplier), Divisor, Remainder);\r
+ }\r
+}\r
+\r
+/**\r
+ Return the elapsed tick count from CurrentTick.\r
+\r
+ @param CurrentTick On input, the previous tick count.\r
+ On output, the current tick count.\r
+ @param StartTick The value the performance counter starts with when it\r
+ rolls over.\r
+ @param EndTick The value that the performance counter ends with before\r
+ it rolls over.\r
+\r
+ @return The elapsed tick count from CurrentTick.\r
+**/\r
+UINT64\r
+GetElapsedTick (\r
+ UINT64 *CurrentTick,\r
+ UINT64 StartTick,\r
+ UINT64 EndTick\r
+ )\r
+{\r
+ UINT64 PreviousTick;\r
+\r
+ PreviousTick = *CurrentTick;\r
+ *CurrentTick = GetPerformanceCounter();\r
+ if (StartTick < EndTick) {\r
+ return *CurrentTick - PreviousTick;\r
+ } else {\r
+ return PreviousTick - *CurrentTick;\r
+ }\r
+}\r
+\r
/**\r
Polls an address in memory mapped I/O space until an exit condition is met,\r
or a timeout occurs.\r
EFI_STATUS Status;\r
UINT64 NumberOfTicks;\r
UINT32 Remainder;\r
+ UINT64 StartTick;\r
+ UINT64 EndTick;\r
+ UINT64 CurrentTick;\r
+ UINT64 ElapsedTick;\r
+ UINT64 Frequency;\r
\r
if (Result == NULL) {\r
return EFI_INVALID_PARAMETER;\r
return EFI_SUCCESS;\r
\r
} else {\r
-\r
- //\r
- // Determine the proper # of metronome ticks to wait for polling the\r
- // location. The nuber of ticks is Roundup (Delay /\r
- // mMetronome->TickPeriod)+1\r
- // The "+1" to account for the possibility of the first tick being short\r
- // because we started in the middle of a tick.\r
//\r
- // BugBug: overriding mMetronome->TickPeriod with UINT32 until Metronome\r
- // protocol definition is updated.\r
+ // NumberOfTicks = Frenquency * Delay / EFI_TIMER_PERIOD_SECONDS(1)\r
//\r
- NumberOfTicks = DivU64x32Remainder (Delay, (UINT32) mMetronome->TickPeriod,\r
- &Remainder);\r
- if (Remainder != 0) {\r
- NumberOfTicks += 1;\r
+ Frequency = GetPerformanceCounterProperties (&StartTick, &EndTick);\r
+ NumberOfTicks = MultThenDivU64x64x32 (Frequency, Delay, (UINT32)EFI_TIMER_PERIOD_SECONDS(1), &Remainder);\r
+ if (Remainder >= (UINTN)EFI_TIMER_PERIOD_SECONDS(1) / 2) {\r
+ NumberOfTicks++;\r
}\r
- NumberOfTicks += 1;\r
-\r
- while (NumberOfTicks != 0) {\r
-\r
- mMetronome->WaitForTick (mMetronome, 1);\r
-\r
+ for ( ElapsedTick = 0, CurrentTick = GetPerformanceCounter()\r
+ ; ElapsedTick <= NumberOfTicks\r
+ ; ElapsedTick += GetElapsedTick (&CurrentTick, StartTick, EndTick)\r
+ ) {\r
Status = This->Mem.Read (This, Width, Address, 1, Result);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
if ((*Result & Mask) == Value) {\r
return EFI_SUCCESS;\r
}\r
-\r
- NumberOfTicks -= 1;\r
}\r
}\r
return EFI_TIMEOUT;\r
EFI_STATUS Status;\r
UINT64 NumberOfTicks;\r
UINT32 Remainder;\r
+ UINT64 StartTick;\r
+ UINT64 EndTick;\r
+ UINT64 CurrentTick;\r
+ UINT64 ElapsedTick;\r
+ UINT64 Frequency;\r
\r
//\r
// No matter what, always do a single poll.\r
return EFI_SUCCESS;\r
\r
} else {\r
-\r
//\r
- // Determine the proper # of metronome ticks to wait for polling the\r
- // location. The number of ticks is Roundup (Delay /\r
- // mMetronome->TickPeriod)+1\r
- // The "+1" to account for the possibility of the first tick being short\r
- // because we started in the middle of a tick.\r
+ // NumberOfTicks = Frenquency * Delay / EFI_TIMER_PERIOD_SECONDS(1)\r
//\r
- NumberOfTicks = DivU64x32Remainder (Delay, (UINT32)mMetronome->TickPeriod,\r
- &Remainder);\r
- if (Remainder != 0) {\r
- NumberOfTicks += 1;\r
+ Frequency = GetPerformanceCounterProperties (&StartTick, &EndTick);\r
+ NumberOfTicks = MultThenDivU64x64x32 (Frequency, Delay, (UINT32)EFI_TIMER_PERIOD_SECONDS(1), &Remainder);\r
+ if (Remainder >= (UINTN)EFI_TIMER_PERIOD_SECONDS(1) / 2) {\r
+ NumberOfTicks++;\r
}\r
- NumberOfTicks += 1;\r
-\r
- while (NumberOfTicks != 0) {\r
-\r
- mMetronome->WaitForTick (mMetronome, 1);\r
-\r
+ for ( ElapsedTick = 0, CurrentTick = GetPerformanceCounter()\r
+ ; ElapsedTick <= NumberOfTicks\r
+ ; ElapsedTick += GetElapsedTick (&CurrentTick, StartTick, EndTick)\r
+ ) {\r
Status = This->Io.Read (This, Width, Address, 1, Result);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
if ((*Result & Mask) == Value) {\r
return EFI_SUCCESS;\r
}\r
-\r
- NumberOfTicks -= 1;\r
}\r
}\r
return EFI_TIMEOUT;\r
\r
RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
\r
- if (mIoMmuProtocol != NULL) {\r
+ if (mIoMmu != NULL) {\r
if (!RootBridge->DmaAbove4G) {\r
//\r
// Clear 64bit support\r
Operation = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) (Operation - EfiPciOperationBusMasterRead64);\r
}\r
}\r
- Status = mIoMmuProtocol->Map (\r
- mIoMmuProtocol,\r
- (EDKII_IOMMU_OPERATION) Operation,\r
- HostAddress,\r
- NumberOfBytes,\r
- DeviceAddress,\r
- Mapping\r
- );\r
+ Status = mIoMmu->Map (\r
+ mIoMmu,\r
+ (EDKII_IOMMU_OPERATION) Operation,\r
+ HostAddress,\r
+ NumberOfBytes,\r
+ DeviceAddress,\r
+ Mapping\r
+ );\r
return Status;\r
}\r
\r
PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
EFI_STATUS Status;\r
\r
- if (mIoMmuProtocol != NULL) {\r
- Status = mIoMmuProtocol->Unmap (\r
- mIoMmuProtocol,\r
- Mapping\r
- );\r
+ if (mIoMmu != NULL) {\r
+ Status = mIoMmu->Unmap (\r
+ mIoMmu,\r
+ Mapping\r
+ );\r
return Status;\r
}\r
\r
\r
RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
\r
- if (mIoMmuProtocol != NULL) {\r
+ if (mIoMmu != NULL) {\r
if (!RootBridge->DmaAbove4G) {\r
//\r
// Clear DUAL_ADDRESS_CYCLE\r
//\r
Attributes &= ~((UINT64) EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE);\r
}\r
- Status = mIoMmuProtocol->AllocateBuffer (\r
- mIoMmuProtocol,\r
- Type,\r
- MemoryType,\r
- Pages,\r
- HostAddress,\r
- Attributes\r
- );\r
+ Status = mIoMmu->AllocateBuffer (\r
+ mIoMmu,\r
+ Type,\r
+ MemoryType,\r
+ Pages,\r
+ HostAddress,\r
+ Attributes\r
+ );\r
return Status;\r
}\r
\r
{\r
EFI_STATUS Status;\r
\r
- if (mIoMmuProtocol != NULL) {\r
- Status = mIoMmuProtocol->FreeBuffer (\r
- mIoMmuProtocol,\r
- Pages,\r
- HostAddress\r
- );\r
+ if (mIoMmu != NULL) {\r
+ Status = mIoMmu->FreeBuffer (\r
+ mIoMmu,\r
+ Pages,\r
+ HostAddress\r
+ );\r
return Status;\r
}\r
\r