2 * Implementation of the PCI Root Bridge Protocol for XPress-RICH3 PCIe Root Complex
4 * Copyright (c) 2011-2015, ARM Ltd. All rights reserved.
6 * This program and the accompanying materials
7 * are licensed and made available under the terms and conditions of the BSD License
8 * which accompanies this distribution. The full text of the license may be found at
9 * http://opensource.org/licenses/bsd-license.php
11 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "PciHostBridge.h"
18 #include <Library/DevicePathLib.h>
19 #include <Library/DmaLib.h>
21 #define CPUIO_FROM_ROOT_BRIDGE_INSTANCE(Instance) (Instance->HostBridge->CpuIo)
22 #define METRONOME_FROM_ROOT_BRIDGE_INSTANCE(Instance) (Instance->HostBridge->Metronome)
25 * PCI Root Bridge Instance Templates
27 STATIC CONST EFI_PCI_ROOT_BRIDGE_DEVICE_PATH gDevicePathTemplate
= {
31 { (UINT8
) (sizeof (ACPI_HID_DEVICE_PATH
)),
32 (UINT8
) ((sizeof (ACPI_HID_DEVICE_PATH
)) >> 8) }
39 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
40 { END_DEVICE_PATH_LENGTH
, 0 }
44 STATIC CONST EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL gIoTemplate
= {
73 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR SpaceDesp
[ResTypeMax
+1];
74 EFI_ACPI_END_TAG_DESCRIPTOR EndDesp
;
75 } RESOURCE_CONFIGURATION
;
78 RESOURCE_CONFIGURATION Configuration
= {
79 {{ACPI_ADDRESS_SPACE_DESCRIPTOR
, 0x2B, ACPI_ADDRESS_SPACE_TYPE_IO
, 0, 0, 0, 0, 0, 0, 0},
80 {ACPI_ADDRESS_SPACE_DESCRIPTOR
, 0x2B, ACPI_ADDRESS_SPACE_TYPE_MEM
, 0, 0, 32, 0, 0, 0, 0},
81 {ACPI_ADDRESS_SPACE_DESCRIPTOR
, 0x2B, ACPI_ADDRESS_SPACE_TYPE_MEM
, 0, 6, 32, 0, 0, 0, 0},
82 {ACPI_ADDRESS_SPACE_DESCRIPTOR
, 0x2B, ACPI_ADDRESS_SPACE_TYPE_MEM
, 0, 0, 64, 0, 0, 0, 0},
83 {ACPI_ADDRESS_SPACE_DESCRIPTOR
, 0x2B, ACPI_ADDRESS_SPACE_TYPE_MEM
, 0, 6, 64, 0, 0, 0, 0},
84 {ACPI_ADDRESS_SPACE_DESCRIPTOR
, 0x2B, ACPI_ADDRESS_SPACE_TYPE_BUS
, 0, 0, 0, 0, 255, 0, 255}},
85 {ACPI_END_TAG_DESCRIPTOR
, 0}
91 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
92 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width
,
101 UINT64 NumberOfTicks
;
103 PCI_ROOT_BRIDGE_INSTANCE
*RootBridgeInstance
;
104 EFI_METRONOME_ARCH_PROTOCOL
*Metronome
;
106 PCI_TRACE ("PciRbPollMem()");
108 RootBridgeInstance
= INSTANCE_FROM_ROOT_BRIDGE_IO_THIS (This
);
109 Metronome
= METRONOME_FROM_ROOT_BRIDGE_INSTANCE (RootBridgeInstance
);
111 if (Result
== NULL
) {
112 return EFI_INVALID_PARAMETER
;
115 if (Width
> EfiPciWidthUint64
) {
116 return EFI_INVALID_PARAMETER
;
119 // No matter what, always do a single poll.
120 Status
= This
->Mem
.Read (This
, Width
, Address
, 1, Result
);
121 if (EFI_ERROR (Status
)) {
124 if ((*Result
& Mask
) == Value
) {
132 NumberOfTicks
= DivU64x32Remainder (Delay
, (UINT32
) Metronome
->TickPeriod
, &Remainder
);
133 if (Remainder
!= 0) {
138 while (NumberOfTicks
) {
139 Metronome
->WaitForTick (Metronome
, 1);
141 Status
= This
->Mem
.Read (This
, Width
, Address
, 1, Result
);
142 if (EFI_ERROR (Status
)) {
146 if ((*Result
& Mask
) == Value
) {
158 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
159 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width
,
168 UINT64 NumberOfTicks
;
170 PCI_ROOT_BRIDGE_INSTANCE
*RootBridgeInstance
;
171 EFI_METRONOME_ARCH_PROTOCOL
*Metronome
;
173 PCI_TRACE ("PciRbPollIo()");
175 RootBridgeInstance
= INSTANCE_FROM_ROOT_BRIDGE_IO_THIS (This
);
176 Metronome
= METRONOME_FROM_ROOT_BRIDGE_INSTANCE (RootBridgeInstance
);
178 if (Result
== NULL
) {
179 return EFI_INVALID_PARAMETER
;
182 if (Width
> EfiPciWidthUint64
) {
183 return EFI_INVALID_PARAMETER
;
186 // No matter what, always do a single poll.
187 Status
= This
->Io
.Read (This
, Width
, Address
, 1, Result
);
188 if (EFI_ERROR (Status
)) {
191 if ((*Result
& Mask
) == Value
) {
199 NumberOfTicks
= DivU64x32Remainder (Delay
, (UINT32
) Metronome
->TickPeriod
, &Remainder
);
200 if (Remainder
!= 0) {
205 while (NumberOfTicks
) {
206 Metronome
->WaitForTick (Metronome
, 1);
208 Status
= This
->Io
.Read (This
, Width
, Address
, 1, Result
);
209 if (EFI_ERROR (Status
)) {
213 if ((*Result
& Mask
) == Value
) {
225 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
226 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width
,
232 PCI_ROOT_BRIDGE_INSTANCE
*RootBridgeInstance
;
233 EFI_CPU_IO2_PROTOCOL
*CpuIo
;
235 PCI_TRACE ("PciRbMemRead()");
237 RootBridgeInstance
= INSTANCE_FROM_ROOT_BRIDGE_IO_THIS (This
);
238 CpuIo
= CPUIO_FROM_ROOT_BRIDGE_INSTANCE (RootBridgeInstance
);
240 if (Buffer
== NULL
) {
241 return EFI_INVALID_PARAMETER
;
244 if (Width
>= EfiPciWidthMaximum
) {
245 return EFI_INVALID_PARAMETER
;
248 if (((Address
< PCI_MEM32_BASE
) || (Address
> (PCI_MEM32_BASE
+ PCI_MEM32_SIZE
))) &&
249 ((Address
< PCI_MEM64_BASE
) || (Address
> (PCI_MEM64_BASE
+ PCI_MEM64_SIZE
)))) {
250 return EFI_INVALID_PARAMETER
;
253 return CpuIo
->Mem
.Read (CpuIo
, (EFI_CPU_IO_PROTOCOL_WIDTH
)Width
, Address
, Count
, Buffer
);
258 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
259 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width
,
265 PCI_ROOT_BRIDGE_INSTANCE
*RootBridgeInstance
;
266 EFI_CPU_IO2_PROTOCOL
*CpuIo
;
268 PCI_TRACE ("PciRbMemWrite()");
270 RootBridgeInstance
= INSTANCE_FROM_ROOT_BRIDGE_IO_THIS (This
);
271 CpuIo
= CPUIO_FROM_ROOT_BRIDGE_INSTANCE (RootBridgeInstance
);
273 if (Buffer
== NULL
) {
274 return EFI_INVALID_PARAMETER
;
277 if (Width
>= EfiPciWidthMaximum
) {
278 return EFI_INVALID_PARAMETER
;
281 if (((Address
< PCI_MEM32_BASE
) || (Address
> (PCI_MEM32_BASE
+ PCI_MEM32_SIZE
))) &&
282 ((Address
< PCI_MEM64_BASE
) || (Address
> (PCI_MEM64_BASE
+ PCI_MEM64_SIZE
)))) {
283 return EFI_INVALID_PARAMETER
;
286 return CpuIo
->Mem
.Write (CpuIo
, (EFI_CPU_IO_PROTOCOL_WIDTH
)Width
, Address
, Count
, Buffer
);
291 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
292 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width
,
298 PCI_TRACE ("PciRbIoRead()");
300 if (Buffer
== NULL
) {
301 return EFI_INVALID_PARAMETER
;
304 if (Width
>= EfiPciWidthMaximum
) {
305 return EFI_INVALID_PARAMETER
;
308 // IO currently unsupported
309 return EFI_INVALID_PARAMETER
;
314 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
315 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width
,
321 PCI_TRACE ("PciRbIoWrite()");
323 if (Buffer
== NULL
) {
324 return EFI_INVALID_PARAMETER
;
327 if (Width
>= EfiPciWidthMaximum
) {
328 return EFI_INVALID_PARAMETER
;
331 // IO currently unsupported
332 return EFI_INVALID_PARAMETER
;
337 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
338 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width
,
339 IN UINT64 EfiAddress
,
345 PCI_ROOT_BRIDGE_INSTANCE
*RootBridgeInstance
;
346 EFI_CPU_IO2_PROTOCOL
*CpuIo
;
347 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS
*EfiPciAddress
;
350 EfiPciAddress
= (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS
*)&EfiAddress
;
351 RootBridgeInstance
= INSTANCE_FROM_ROOT_BRIDGE_IO_THIS (This
);
352 CpuIo
= CPUIO_FROM_ROOT_BRIDGE_INSTANCE (RootBridgeInstance
);
354 if (Buffer
== NULL
) {
355 return EFI_INVALID_PARAMETER
;
358 if (Width
>= EfiPciWidthMaximum
) {
359 return EFI_INVALID_PARAMETER
;
362 if (EfiPciAddress
->ExtendedRegister
) {
363 Offset
= EfiPciAddress
->ExtendedRegister
;
365 Offset
= EfiPciAddress
->Register
;
368 // The UEFI PCI enumerator scans for devices at all possible addresses,
369 // and ignores some PCI rules - this results in some hardware being
370 // detected multiple times. We work around this by faking absent
372 if ((EfiPciAddress
->Bus
== 0) && ((EfiPciAddress
->Device
!= 0) || (EfiPciAddress
->Function
!= 0))) {
373 *((UINT32
*)Buffer
) = 0xffffffff;
376 if ((EfiPciAddress
->Bus
== 1) && ((EfiPciAddress
->Device
!= 0) || (EfiPciAddress
->Function
!= 0))) {
377 *((UINT32
*)Buffer
) = 0xffffffff;
381 // Work around incorrect class ID in the root bridge
382 if ((EfiPciAddress
->Bus
== 0) && (EfiPciAddress
->Device
== 0) && (EfiPciAddress
->Function
== 0) && (Offset
== 8)) {
383 *((UINT32
*)Buffer
) = 0x06040001;
387 Address
= PCI_ECAM_BASE
+ ((EfiPciAddress
->Bus
<< 20) |
388 (EfiPciAddress
->Device
<< 15) |
389 (EfiPciAddress
->Function
<< 12) | Offset
);
391 if ((Address
< PCI_ECAM_BASE
) || (Address
> PCI_ECAM_BASE
+ PCI_ECAM_SIZE
)) {
392 return EFI_INVALID_PARAMETER
;
395 return CpuIo
->Mem
.Read (CpuIo
, (EFI_CPU_IO_PROTOCOL_WIDTH
)Width
, Address
, Count
, Buffer
);
400 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
401 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width
,
402 IN UINT64 EfiAddress
,
408 PCI_ROOT_BRIDGE_INSTANCE
*RootBridgeInstance
;
409 EFI_CPU_IO2_PROTOCOL
*CpuIo
;
410 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS
*EfiPciAddress
;
413 EfiPciAddress
= (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS
*)&EfiAddress
;
414 RootBridgeInstance
= INSTANCE_FROM_ROOT_BRIDGE_IO_THIS (This
);
415 CpuIo
= CPUIO_FROM_ROOT_BRIDGE_INSTANCE (RootBridgeInstance
);
417 if (Buffer
== NULL
) {
418 return EFI_INVALID_PARAMETER
;
421 if (Width
>= EfiPciWidthMaximum
) {
422 return EFI_INVALID_PARAMETER
;
425 if (EfiPciAddress
->ExtendedRegister
)
426 Offset
= EfiPciAddress
->ExtendedRegister
;
428 Offset
= EfiPciAddress
->Register
;
430 Address
= PCI_ECAM_BASE
+ ((EfiPciAddress
->Bus
<< 20) |
431 (EfiPciAddress
->Device
<< 15) |
432 (EfiPciAddress
->Function
<< 12) | Offset
);
434 if (Address
< PCI_ECAM_BASE
|| Address
> PCI_ECAM_BASE
+ PCI_ECAM_SIZE
) {
435 return EFI_INVALID_PARAMETER
;
438 return CpuIo
->Mem
.Write (CpuIo
, (EFI_CPU_IO_PROTOCOL_WIDTH
)Width
, Address
, Count
, Buffer
);
443 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
444 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width
,
445 IN UINT64 DestAddress
,
446 IN UINT64 SrcAddress
,
456 PCI_TRACE ("PciRbCopyMem()");
458 if (Width
> EfiPciWidthUint64
) {
459 return EFI_INVALID_PARAMETER
;
462 if (DestAddress
== SrcAddress
) {
466 Stride
= (UINTN
)(1 << Width
);
469 if ((DestAddress
> SrcAddress
) && (DestAddress
< (SrcAddress
+ Count
* Stride
))) {
471 SrcAddress
= SrcAddress
+ (Count
-1) * Stride
;
472 DestAddress
= DestAddress
+ (Count
-1) * Stride
;
475 for (Index
= 0; Index
< Count
; Index
++) {
476 Status
= PciRbMemRead (
483 if (EFI_ERROR (Status
)) {
486 Status
= PciRbMemWrite (
493 if (EFI_ERROR (Status
)) {
497 SrcAddress
+= Stride
;
498 DestAddress
+= Stride
;
500 SrcAddress
-= Stride
;
501 DestAddress
-= Stride
;
509 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
510 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation
,
511 IN VOID
*HostAddress
,
512 IN OUT UINTN
*NumberOfBytes
,
513 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
517 DMA_MAP_OPERATION DmaOperation
;
519 PCI_TRACE ("PciRbMap()");
521 if (Operation
== EfiPciOperationBusMasterRead
) {
522 DmaOperation
= MapOperationBusMasterRead
;
523 } else if (Operation
== EfiPciOperationBusMasterWrite
) {
524 DmaOperation
= MapOperationBusMasterWrite
;
525 } else if (Operation
== EfiPciOperationBusMasterCommonBuffer
) {
526 DmaOperation
= MapOperationBusMasterCommonBuffer
;
528 return EFI_INVALID_PARAMETER
;
530 return DmaMap (DmaOperation
, HostAddress
, NumberOfBytes
, DeviceAddress
, Mapping
);
535 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
539 PCI_TRACE ("PciRbUnMap()");
540 return DmaUnmap (Mapping
);
544 PciRbAllocateBuffer (
545 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
546 IN EFI_ALLOCATE_TYPE Type
,
547 IN EFI_MEMORY_TYPE MemoryType
,
549 IN OUT VOID
**HostAddress
,
553 PCI_TRACE ("PciRbAllocateBuffer()");
555 if (Attributes
& EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER
) {
556 return EFI_UNSUPPORTED
;
559 return DmaAllocateBuffer (MemoryType
, Pages
, HostAddress
);
564 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
569 PCI_TRACE ("PciRbFreeBuffer()");
570 return DmaFreeBuffer (Pages
, HostAddress
);
575 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
578 PCI_TRACE ("PciRbFlush()");
580 //TODO: Not supported yet
587 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
588 IN UINT64 Attributes
,
589 IN OUT UINT64
*ResourceBase
,
590 IN OUT UINT64
*ResourceLength
593 PCI_ROOT_BRIDGE_INSTANCE
*RootBridgeInstance
;
595 PCI_TRACE ("PciRbSetAttributes()");
597 RootBridgeInstance
= INSTANCE_FROM_ROOT_BRIDGE_IO_THIS (This
);
600 if ((Attributes
& (~(RootBridgeInstance
->Supports
))) != 0) {
601 return EFI_UNSUPPORTED
;
605 //TODO: Cannot allowed to change attributes
606 if (Attributes
& ~RootBridgeInstance
->Attributes
) {
607 return EFI_UNSUPPORTED
;
615 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
616 OUT UINT64
*Supported
,
617 OUT UINT64
*Attributes
620 PCI_ROOT_BRIDGE_INSTANCE
*RootBridgeInstance
;
622 PCI_TRACE ("PciRbGetAttributes()");
624 RootBridgeInstance
= INSTANCE_FROM_ROOT_BRIDGE_IO_THIS (This
);
626 if (Attributes
== NULL
&& Supported
== NULL
) {
627 return EFI_INVALID_PARAMETER
;
630 // Set the return value for Supported and Attributes
632 *Supported
= RootBridgeInstance
->Supports
;
636 *Attributes
= RootBridgeInstance
->Attributes
;
644 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*This
,
648 PCI_ROOT_BRIDGE_INSTANCE
*RootBridge
;
651 PCI_TRACE ("PciRbConfiguration()");
653 RootBridge
= INSTANCE_FROM_ROOT_BRIDGE_IO_THIS (This
);
655 for (Index
= 0; Index
< ResTypeMax
; Index
++) {
656 //if (ResAlloc[Index].Length != 0) => Resource allocated
657 if (RootBridge
->ResAlloc
[Index
].Length
!= 0) {
658 Configuration
.SpaceDesp
[Index
].AddrRangeMin
= RootBridge
->ResAlloc
[Index
].Base
;
659 Configuration
.SpaceDesp
[Index
].AddrRangeMax
= RootBridge
->ResAlloc
[Index
].Base
+ RootBridge
->ResAlloc
[Index
].Length
- 1;
660 Configuration
.SpaceDesp
[Index
].AddrLen
= RootBridge
->ResAlloc
[Index
].Length
;
664 // Set up Configuration for the bus
665 Configuration
.SpaceDesp
[Index
].AddrRangeMin
= RootBridge
->BusStart
;
666 Configuration
.SpaceDesp
[Index
].AddrLen
= RootBridge
->BusLength
;
668 *Resources
= &Configuration
;
674 IN PCI_HOST_BRIDGE_INSTANCE
*HostBridge
,
675 IN UINT32 PciAcpiUid
,
676 IN UINT64 MemAllocAttributes
679 PCI_ROOT_BRIDGE_INSTANCE
* RootBridge
;
682 PCI_TRACE ("PciRbConstructor()");
684 // Allocate Memory for the Instance from a Template
685 RootBridge
= AllocateZeroPool (sizeof (PCI_ROOT_BRIDGE_INSTANCE
));
686 if (RootBridge
== NULL
) {
687 PCI_TRACE ("PciRbConstructor(): ERROR: Out of Resources");
688 return EFI_OUT_OF_RESOURCES
;
690 RootBridge
->Signature
= PCI_ROOT_BRIDGE_SIGNATURE
;
691 CopyMem (&(RootBridge
->DevicePath
), &gDevicePathTemplate
, sizeof (EFI_PCI_ROOT_BRIDGE_DEVICE_PATH
));
692 CopyMem (&(RootBridge
->Io
), &gIoTemplate
, sizeof (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
));
695 RootBridge
->Io
.ParentHandle
= HostBridge
->Handle
;
697 // Attach the Root Bridge to the PCI Host Bridge Instance
698 RootBridge
->HostBridge
= HostBridge
;
700 // Set Device Path for this Root Bridge
701 RootBridge
->DevicePath
.Acpi
.UID
= PciAcpiUid
;
703 RootBridge
->BusStart
= FixedPcdGet32 (PcdPciBusMin
);
704 RootBridge
->BusLength
= FixedPcdGet32 (PcdPciBusMax
) - FixedPcdGet32 (PcdPciBusMin
) + 1;
707 RootBridge
->Supports
= 0;
708 RootBridge
->Attributes
= 0;
710 // Install Protocol Instances. It will also generate a device handle for the PCI Root Bridge
711 Status
= gBS
->InstallMultipleProtocolInterfaces (
713 &gEfiDevicePathProtocolGuid
, &RootBridge
->DevicePath
,
714 &gEfiPciRootBridgeIoProtocolGuid
, &RootBridge
->Io
,
717 ASSERT (RootBridge
->Signature
== PCI_ROOT_BRIDGE_SIGNATURE
);
718 if (EFI_ERROR (Status
)) {
719 PCI_TRACE ("PciRbConstructor(): ERROR: Fail to install Protocol Interfaces");
720 FreePool (RootBridge
);
721 return EFI_DEVICE_ERROR
;
724 HostBridge
->RootBridge
= RootBridge
;
730 IN PCI_ROOT_BRIDGE_INSTANCE
* RootBridge
735 Status
= gBS
->UninstallMultipleProtocolInterfaces (
737 &gEfiDevicePathProtocolGuid
, &RootBridge
->DevicePath
,
738 &gEfiPciRootBridgeIoProtocolGuid
, &RootBridge
->Io
,
742 FreePool (RootBridge
);