3 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
4 Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>
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 "NonDiscoverablePciDeviceIo.h"
18 #include <Library/DxeServicesTableLib.h>
20 #include <IndustryStandard/Acpi.h>
22 #include <Protocol/PciRootBridgeIo.h>
25 EFI_PHYSICAL_ADDRESS AllocAddress
;
27 EFI_PCI_IO_PROTOCOL_OPERATION Operation
;
29 } NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO
;
32 // Get the resource associated with BAR number 'BarIndex'.
37 IN NON_DISCOVERABLE_PCI_DEVICE
*Dev
,
39 OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
**Descriptor
42 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Desc
;
44 if (BarIndex
< Dev
->BarOffset
) {
48 BarIndex
-= (UINT8
)Dev
->BarOffset
;
50 for (Desc
= Dev
->Device
->Resources
;
51 Desc
->Desc
!= ACPI_END_TAG_DESCRIPTOR
;
52 Desc
= (VOID
*)((UINT8
*)Desc
+ Desc
->Len
+ 3)) {
68 IN EFI_PCI_IO_PROTOCOL
*This
,
69 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
79 return EFI_UNSUPPORTED
;
86 IN EFI_PCI_IO_PROTOCOL
*This
,
87 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
97 return EFI_UNSUPPORTED
;
104 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
112 volatile UINT8
*Dst8
;
113 volatile UINT16
*Dst16
;
114 volatile UINT32
*Dst32
;
115 volatile CONST UINT8
*Src8
;
116 volatile CONST UINT16
*Src16
;
117 volatile CONST UINT32
*Src32
;
120 // Loop for each iteration and move the data
122 switch (Width
& 0x3) {
123 case EfiPciWidthUint8
:
126 for (;Count
> 0; Count
--, Dst8
+= DstStride
, Src8
+= SrcStride
) {
130 case EfiPciWidthUint16
:
131 Dst16
= (UINT16
*)Dst
;
132 Src16
= (UINT16
*)Src
;
133 for (;Count
> 0; Count
--, Dst16
+= DstStride
, Src16
+= SrcStride
) {
137 case EfiPciWidthUint32
:
138 Dst32
= (UINT32
*)Dst
;
139 Src32
= (UINT32
*)Src
;
140 for (;Count
> 0; Count
--, Dst32
+= DstStride
, Src32
+= SrcStride
) {
145 return EFI_INVALID_PARAMETER
;
155 IN EFI_PCI_IO_PROTOCOL
*This
,
156 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
163 NON_DISCOVERABLE_PCI_DEVICE
*Dev
;
166 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Desc
;
169 if (Buffer
== NULL
) {
170 return EFI_INVALID_PARAMETER
;
173 Dev
= NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This
);
176 // Only allow accesses to the BARs we emulate
178 Status
= GetBarResource (Dev
, BarIndex
, &Desc
);
179 if (EFI_ERROR (Status
)) {
183 if (Offset
+ (Count
<< (Width
& 0x3)) > Desc
->AddrLen
) {
184 return EFI_UNSUPPORTED
;
187 Address
= (VOID
*)(UINTN
)(Desc
->AddrRangeMin
+ Offset
);
188 AlignMask
= (1 << (Width
& 0x03)) - 1;
189 if ((UINTN
)Address
& AlignMask
) {
190 return EFI_INVALID_PARAMETER
;
194 case EfiPciIoWidthUint8
:
195 case EfiPciIoWidthUint16
:
196 case EfiPciIoWidthUint32
:
197 case EfiPciIoWidthUint64
:
198 return PciIoMemRW (Width
, Count
, 1, Buffer
, 1, Address
);
200 case EfiPciIoWidthFifoUint8
:
201 case EfiPciIoWidthFifoUint16
:
202 case EfiPciIoWidthFifoUint32
:
203 case EfiPciIoWidthFifoUint64
:
204 return PciIoMemRW (Width
, Count
, 1, Buffer
, 0, Address
);
206 case EfiPciIoWidthFillUint8
:
207 case EfiPciIoWidthFillUint16
:
208 case EfiPciIoWidthFillUint32
:
209 case EfiPciIoWidthFillUint64
:
210 return PciIoMemRW (Width
, Count
, 0, Buffer
, 1, Address
);
215 return EFI_INVALID_PARAMETER
;
222 IN EFI_PCI_IO_PROTOCOL
*This
,
223 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
230 NON_DISCOVERABLE_PCI_DEVICE
*Dev
;
233 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Desc
;
236 if (Buffer
== NULL
) {
237 return EFI_INVALID_PARAMETER
;
240 Dev
= NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This
);
243 // Only allow accesses to the BARs we emulate
245 Status
= GetBarResource (Dev
, BarIndex
, &Desc
);
246 if (EFI_ERROR (Status
)) {
250 if (Offset
+ (Count
<< (Width
& 0x3)) > Desc
->AddrLen
) {
251 return EFI_UNSUPPORTED
;
254 Address
= (VOID
*)(UINTN
)(Desc
->AddrRangeMin
+ Offset
);
255 AlignMask
= (1 << (Width
& 0x03)) - 1;
256 if ((UINTN
)Address
& AlignMask
) {
257 return EFI_INVALID_PARAMETER
;
261 case EfiPciIoWidthUint8
:
262 case EfiPciIoWidthUint16
:
263 case EfiPciIoWidthUint32
:
264 case EfiPciIoWidthUint64
:
265 return PciIoMemRW (Width
, Count
, 1, Address
, 1, Buffer
);
267 case EfiPciIoWidthFifoUint8
:
268 case EfiPciIoWidthFifoUint16
:
269 case EfiPciIoWidthFifoUint32
:
270 case EfiPciIoWidthFifoUint64
:
271 return PciIoMemRW (Width
, Count
, 0, Address
, 1, Buffer
);
273 case EfiPciIoWidthFillUint8
:
274 case EfiPciIoWidthFillUint16
:
275 case EfiPciIoWidthFillUint32
:
276 case EfiPciIoWidthFillUint64
:
277 return PciIoMemRW (Width
, Count
, 1, Address
, 0, Buffer
);
282 return EFI_INVALID_PARAMETER
;
289 IN EFI_PCI_IO_PROTOCOL
*This
,
290 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
298 return EFI_UNSUPPORTED
;
305 IN EFI_PCI_IO_PROTOCOL
*This
,
306 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
314 return EFI_UNSUPPORTED
;
321 IN EFI_PCI_IO_PROTOCOL
*This
,
322 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
328 NON_DISCOVERABLE_PCI_DEVICE
*Dev
;
332 if (Width
< 0 || Width
>= EfiPciIoWidthMaximum
|| Buffer
== NULL
) {
333 return EFI_INVALID_PARAMETER
;
336 Dev
= NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This
);
337 Address
= (UINT8
*)&Dev
->ConfigSpace
+ Offset
;
338 Length
= Count
<< ((UINTN
)Width
& 0x3);
340 if (Offset
+ Length
> sizeof (Dev
->ConfigSpace
)) {
342 // Read all zeroes for config space accesses beyond the first
345 Length
-= sizeof (Dev
->ConfigSpace
) - Offset
;
346 ZeroMem ((UINT8
*)Buffer
+ sizeof (Dev
->ConfigSpace
) - Offset
, Length
);
348 Count
-= Length
>> ((UINTN
)Width
& 0x3);
350 return PciIoMemRW (Width
, Count
, 1, Buffer
, 1, Address
);
357 IN EFI_PCI_IO_PROTOCOL
*This
,
358 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
364 NON_DISCOVERABLE_PCI_DEVICE
*Dev
;
367 if (Width
< 0 || Width
>= EfiPciIoWidthMaximum
|| Buffer
== NULL
) {
368 return EFI_INVALID_PARAMETER
;
371 Dev
= NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This
);
372 Address
= (UINT8
*)&Dev
->ConfigSpace
+ Offset
;
374 if (Offset
+ (Count
<< ((UINTN
)Width
& 0x3)) > sizeof (Dev
->ConfigSpace
)) {
375 return EFI_UNSUPPORTED
;
378 return PciIoMemRW (Width
, Count
, 1, Address
, 1, Buffer
);
385 IN EFI_PCI_IO_PROTOCOL
*This
,
386 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
387 IN UINT8 DestBarIndex
,
388 IN UINT64 DestOffset
,
389 IN UINT8 SrcBarIndex
,
395 return EFI_UNSUPPORTED
;
402 IN EFI_PCI_IO_PROTOCOL
*This
,
403 IN EFI_PCI_IO_PROTOCOL_OPERATION Operation
,
404 IN VOID
*HostAddress
,
405 IN OUT UINTN
*NumberOfBytes
,
406 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
410 NON_DISCOVERABLE_PCI_DEVICE
*Dev
;
412 NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO
*MapInfo
;
415 // If HostAddress exceeds 4 GB, and this device does not support 64-bit DMA
416 // addressing, we need to allocate a bounce buffer and copy over the data.
418 Dev
= NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This
);
419 if ((Dev
->Attributes
& EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
) == 0 &&
420 (UINTN
)HostAddress
+ *NumberOfBytes
> SIZE_4GB
) {
423 // Bounce buffering is not possible for consistent mappings
425 if (Operation
== EfiPciIoOperationBusMasterCommonBuffer
) {
426 return EFI_UNSUPPORTED
;
429 MapInfo
= AllocatePool (sizeof *MapInfo
);
430 if (MapInfo
== NULL
) {
431 return EFI_OUT_OF_RESOURCES
;
434 MapInfo
->AllocAddress
= MAX_UINT32
;
435 MapInfo
->HostAddress
= HostAddress
;
436 MapInfo
->Operation
= Operation
;
437 MapInfo
->NumberOfBytes
= *NumberOfBytes
;
439 Status
= gBS
->AllocatePages (AllocateMaxAddress
, EfiBootServicesData
,
440 EFI_SIZE_TO_PAGES (MapInfo
->NumberOfBytes
),
441 &MapInfo
->AllocAddress
);
442 if (EFI_ERROR (Status
)) {
444 // If we fail here, it is likely because the system has no memory below
445 // 4 GB to begin with. There is not much we can do about that other than
446 // fail the map request.
449 return EFI_DEVICE_ERROR
;
451 if (Operation
== EfiPciIoOperationBusMasterRead
) {
452 gBS
->CopyMem ((VOID
*)(UINTN
)MapInfo
->AllocAddress
, HostAddress
,
455 *DeviceAddress
= MapInfo
->AllocAddress
;
458 *DeviceAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)HostAddress
;
468 IN EFI_PCI_IO_PROTOCOL
*This
,
472 NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO
*MapInfo
;
475 if (MapInfo
!= NULL
) {
476 if (MapInfo
->Operation
== EfiPciIoOperationBusMasterWrite
) {
477 gBS
->CopyMem (MapInfo
->HostAddress
, (VOID
*)(UINTN
)MapInfo
->AllocAddress
,
478 MapInfo
->NumberOfBytes
);
480 gBS
->FreePages (MapInfo
->AllocAddress
,
481 EFI_SIZE_TO_PAGES (MapInfo
->NumberOfBytes
));
490 CoherentPciIoAllocateBuffer (
491 IN EFI_PCI_IO_PROTOCOL
*This
,
492 IN EFI_ALLOCATE_TYPE Type
,
493 IN EFI_MEMORY_TYPE MemoryType
,
495 OUT VOID
**HostAddress
,
499 NON_DISCOVERABLE_PCI_DEVICE
*Dev
;
500 EFI_PHYSICAL_ADDRESS AllocAddress
;
501 EFI_ALLOCATE_TYPE AllocType
;
504 if ((Attributes
& ~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE
|
505 EFI_PCI_ATTRIBUTE_MEMORY_CACHED
)) != 0) {
506 return EFI_UNSUPPORTED
;
510 // Allocate below 4 GB if the dual address cycle attribute has not
511 // been set. If the system has no memory available below 4 GB, there
512 // is little we can do except propagate the error.
514 Dev
= NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This
);
515 if ((Dev
->Attributes
& EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
) == 0) {
516 AllocAddress
= MAX_UINT32
;
517 AllocType
= AllocateMaxAddress
;
519 AllocType
= AllocateAnyPages
;
522 Status
= gBS
->AllocatePages (AllocType
, MemoryType
, Pages
, &AllocAddress
);
523 if (!EFI_ERROR (Status
)) {
524 *HostAddress
= (VOID
*)(UINTN
)AllocAddress
;
532 CoherentPciIoFreeBuffer (
533 IN EFI_PCI_IO_PROTOCOL
*This
,
538 FreePages (HostAddress
, Pages
);
545 NonCoherentPciIoFreeBuffer (
546 IN EFI_PCI_IO_PROTOCOL
*This
,
551 NON_DISCOVERABLE_PCI_DEVICE
*Dev
;
554 NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION
*Alloc
;
557 Dev
= NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This
);
562 // Find the uncached allocation list entry associated
563 // with this allocation
565 for (Entry
= Dev
->UncachedAllocationList
.ForwardLink
;
566 Entry
!= &Dev
->UncachedAllocationList
;
567 Entry
= Entry
->ForwardLink
) {
569 Alloc
= BASE_CR (Entry
, NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION
, List
);
570 if (Alloc
->HostAddress
== HostAddress
&& Alloc
->NumPages
== Pages
) {
572 // We are freeing the exact allocation we were given
573 // before by AllocateBuffer()
581 ASSERT_EFI_ERROR (EFI_NOT_FOUND
);
582 return EFI_NOT_FOUND
;
585 RemoveEntryList (&Alloc
->List
);
587 Status
= gDS
->SetMemorySpaceAttributes (
588 (EFI_PHYSICAL_ADDRESS
)(UINTN
)HostAddress
,
589 EFI_PAGES_TO_SIZE (Pages
),
591 if (EFI_ERROR (Status
)) {
596 // If we fail to restore the original attributes, it is better to leak the
597 // memory than to return it to the heap
599 FreePages (HostAddress
, Pages
);
609 NonCoherentPciIoAllocateBuffer (
610 IN EFI_PCI_IO_PROTOCOL
*This
,
611 IN EFI_ALLOCATE_TYPE Type
,
612 IN EFI_MEMORY_TYPE MemoryType
,
614 OUT VOID
**HostAddress
,
618 NON_DISCOVERABLE_PCI_DEVICE
*Dev
;
619 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor
;
622 NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION
*Alloc
;
625 Dev
= NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This
);
627 Status
= CoherentPciIoAllocateBuffer (This
, Type
, MemoryType
, Pages
,
628 &AllocAddress
, Attributes
);
629 if (EFI_ERROR (Status
)) {
633 Status
= gDS
->GetMemorySpaceDescriptor (
634 (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocAddress
,
636 if (EFI_ERROR (Status
)) {
640 if ((GcdDescriptor
.Capabilities
& (EFI_MEMORY_WC
| EFI_MEMORY_UC
)) == 0) {
641 Status
= EFI_UNSUPPORTED
;
646 // Set the preferred memory attributes
648 if ((Attributes
& EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE
) != 0 ||
649 (GcdDescriptor
.Capabilities
& EFI_MEMORY_UC
) == 0) {
651 // Use write combining if it was requested, or if it is the only
652 // type supported by the region.
654 MemType
= EFI_MEMORY_WC
;
656 MemType
= EFI_MEMORY_UC
;
659 Alloc
= AllocatePool (sizeof *Alloc
);
664 Alloc
->HostAddress
= AllocAddress
;
665 Alloc
->NumPages
= Pages
;
666 Alloc
->Attributes
= GcdDescriptor
.Attributes
;
669 // Record this allocation in the linked list, so we
670 // can restore the memory space attributes later
672 InsertHeadList (&Dev
->UncachedAllocationList
, &Alloc
->List
);
674 Status
= gDS
->SetMemorySpaceAttributes (
675 (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocAddress
,
676 EFI_PAGES_TO_SIZE (Pages
),
678 if (EFI_ERROR (Status
)) {
682 Status
= mCpu
->FlushDataCache (
684 (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocAddress
,
685 EFI_PAGES_TO_SIZE (Pages
),
686 EfiCpuFlushTypeInvalidate
);
687 if (EFI_ERROR (Status
)) {
691 *HostAddress
= AllocAddress
;
696 RemoveEntryList (&Alloc
->List
);
700 CoherentPciIoFreeBuffer (This
, Pages
, AllocAddress
);
707 NonCoherentPciIoMap (
708 IN EFI_PCI_IO_PROTOCOL
*This
,
709 IN EFI_PCI_IO_PROTOCOL_OPERATION Operation
,
710 IN VOID
*HostAddress
,
711 IN OUT UINTN
*NumberOfBytes
,
712 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
716 NON_DISCOVERABLE_PCI_DEVICE
*Dev
;
718 NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO
*MapInfo
;
721 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor
;
724 MapInfo
= AllocatePool (sizeof *MapInfo
);
725 if (MapInfo
== NULL
) {
726 return EFI_OUT_OF_RESOURCES
;
729 MapInfo
->HostAddress
= HostAddress
;
730 MapInfo
->Operation
= Operation
;
731 MapInfo
->NumberOfBytes
= *NumberOfBytes
;
733 Dev
= NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This
);
736 // If this device does not support 64-bit DMA addressing, we need to allocate
737 // a bounce buffer and copy over the data in case HostAddress >= 4 GB.
739 Bounce
= ((Dev
->Attributes
& EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
) == 0 &&
740 (UINTN
)HostAddress
+ *NumberOfBytes
> SIZE_4GB
);
744 case EfiPciIoOperationBusMasterRead
:
745 case EfiPciIoOperationBusMasterWrite
:
747 // For streaming DMA, it is sufficient if the buffer is aligned to
748 // the CPUs DMA buffer alignment.
750 AlignMask
= mCpu
->DmaBufferAlignment
- 1;
751 if ((((UINTN
) HostAddress
| *NumberOfBytes
) & AlignMask
) == 0) {
756 case EfiPciIoOperationBusMasterCommonBuffer
:
758 // Check whether the host address refers to an uncached mapping.
760 Status
= gDS
->GetMemorySpaceDescriptor (
761 (EFI_PHYSICAL_ADDRESS
)(UINTN
)HostAddress
,
763 if (EFI_ERROR (Status
) ||
764 (GcdDescriptor
.Attributes
& (EFI_MEMORY_WB
|EFI_MEMORY_WT
)) != 0) {
775 if (Operation
== EfiPciIoOperationBusMasterCommonBuffer
) {
776 Status
= EFI_DEVICE_ERROR
;
780 Status
= NonCoherentPciIoAllocateBuffer (This
, AllocateAnyPages
,
781 EfiBootServicesData
, EFI_SIZE_TO_PAGES (MapInfo
->NumberOfBytes
),
782 &AllocAddress
, EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE
);
783 if (EFI_ERROR (Status
)) {
786 MapInfo
->AllocAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocAddress
;
787 if (Operation
== EfiPciIoOperationBusMasterRead
) {
788 gBS
->CopyMem (AllocAddress
, HostAddress
, *NumberOfBytes
);
790 *DeviceAddress
= MapInfo
->AllocAddress
;
792 MapInfo
->AllocAddress
= 0;
793 *DeviceAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)HostAddress
;
796 // We are not using a bounce buffer: the mapping is sufficiently
797 // aligned to allow us to simply flush the caches. Note that cleaning
798 // the caches is necessary for both data directions:
799 // - for bus master read, we want the latest data to be present
801 // - for bus master write, we don't want any stale dirty cachelines that
802 // may be written back unexpectedly, and clobber the data written to
803 // main memory by the device.
805 mCpu
->FlushDataCache (mCpu
, (EFI_PHYSICAL_ADDRESS
)(UINTN
)HostAddress
,
806 *NumberOfBytes
, EfiCpuFlushTypeWriteBack
);
821 NonCoherentPciIoUnmap (
822 IN EFI_PCI_IO_PROTOCOL
*This
,
826 NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO
*MapInfo
;
828 if (Mapping
== NULL
) {
829 return EFI_DEVICE_ERROR
;
833 if (MapInfo
->AllocAddress
!= 0) {
835 // We are using a bounce buffer: copy back the data if necessary,
836 // and free the buffer.
838 if (MapInfo
->Operation
== EfiPciIoOperationBusMasterWrite
) {
839 gBS
->CopyMem (MapInfo
->HostAddress
, (VOID
*)(UINTN
)MapInfo
->AllocAddress
,
840 MapInfo
->NumberOfBytes
);
842 NonCoherentPciIoFreeBuffer (This
,
843 EFI_SIZE_TO_PAGES (MapInfo
->NumberOfBytes
),
844 (VOID
*)(UINTN
)MapInfo
->AllocAddress
);
847 // We are *not* using a bounce buffer: if this is a bus master write,
848 // we have to invalidate the caches so the CPU will see the uncached
849 // data written by the device.
851 if (MapInfo
->Operation
== EfiPciIoOperationBusMasterWrite
) {
852 mCpu
->FlushDataCache (mCpu
,
853 (EFI_PHYSICAL_ADDRESS
)(UINTN
)MapInfo
->HostAddress
,
854 MapInfo
->NumberOfBytes
, EfiCpuFlushTypeInvalidate
);
865 IN EFI_PCI_IO_PROTOCOL
*This
875 IN EFI_PCI_IO_PROTOCOL
*This
,
876 OUT UINTN
*SegmentNumber
,
877 OUT UINTN
*BusNumber
,
878 OUT UINTN
*DeviceNumber
,
879 OUT UINTN
*FunctionNumber
882 if (SegmentNumber
== NULL
||
884 DeviceNumber
== NULL
||
885 FunctionNumber
== NULL
) {
886 return EFI_INVALID_PARAMETER
;
901 IN EFI_PCI_IO_PROTOCOL
*This
,
902 IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation
,
903 IN UINT64 Attributes
,
904 OUT UINT64
*Result OPTIONAL
907 NON_DISCOVERABLE_PCI_DEVICE
*Dev
;
910 Dev
= NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This
);
914 case EfiPciIoAttributeOperationGet
:
915 if (Result
== NULL
) {
916 return EFI_INVALID_PARAMETER
;
918 *Result
= Dev
->Attributes
;
921 case EfiPciIoAttributeOperationSupported
:
922 if (Result
== NULL
) {
923 return EFI_INVALID_PARAMETER
;
925 *Result
= EFI_PCI_DEVICE_ENABLE
| EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
;
928 case EfiPciIoAttributeOperationEnable
:
929 Attributes
|= Dev
->Attributes
;
930 case EfiPciIoAttributeOperationSet
:
931 Enable
= ((~Dev
->Attributes
& Attributes
) & EFI_PCI_DEVICE_ENABLE
) != 0;
932 Dev
->Attributes
= Attributes
;
935 case EfiPciIoAttributeOperationDisable
:
936 Dev
->Attributes
&= ~Attributes
;
940 return EFI_INVALID_PARAMETER
;
944 // If we're setting any of the EFI_PCI_DEVICE_ENABLE bits, perform
945 // the device specific initialization now.
947 if (Enable
&& !Dev
->Enabled
&& Dev
->Device
->Initialize
!= NULL
) {
948 Dev
->Device
->Initialize (Dev
->Device
);
957 PciIoGetBarAttributes (
958 IN EFI_PCI_IO_PROTOCOL
*This
,
960 OUT UINT64
*Supports OPTIONAL
,
961 OUT VOID
**Resources OPTIONAL
964 NON_DISCOVERABLE_PCI_DEVICE
*Dev
;
965 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
, *BarDesc
;
966 EFI_ACPI_END_TAG_DESCRIPTOR
*End
;
969 if (Supports
== NULL
&& Resources
== NULL
) {
970 return EFI_INVALID_PARAMETER
;
973 Dev
= NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This
);
975 Status
= GetBarResource (Dev
, BarIndex
, &BarDesc
);
976 if (EFI_ERROR (Status
)) {
981 // Don't expose any configurable attributes for our emulated BAR
983 if (Supports
!= NULL
) {
987 if (Resources
!= NULL
) {
988 Descriptor
= AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
) +
989 sizeof (EFI_ACPI_END_TAG_DESCRIPTOR
));
990 if (Descriptor
== NULL
) {
991 return EFI_OUT_OF_RESOURCES
;
994 CopyMem (Descriptor
, BarDesc
, sizeof *Descriptor
);
996 End
= (EFI_ACPI_END_TAG_DESCRIPTOR
*) (Descriptor
+ 1);
997 End
->Desc
= ACPI_END_TAG_DESCRIPTOR
;
1000 *Resources
= Descriptor
;
1008 PciIoSetBarAttributes (
1009 IN EFI_PCI_IO_PROTOCOL
*This
,
1010 IN UINT64 Attributes
,
1012 IN OUT UINT64
*Offset
,
1013 IN OUT UINT64
*Length
1017 return EFI_UNSUPPORTED
;
1020 STATIC CONST EFI_PCI_IO_PROTOCOL PciIoTemplate
=
1024 { PciIoMemRead
, PciIoMemWrite
},
1025 { PciIoIoRead
, PciIoIoWrite
},
1026 { PciIoPciRead
, PciIoPciWrite
},
1030 CoherentPciIoAllocateBuffer
,
1031 CoherentPciIoFreeBuffer
,
1035 PciIoGetBarAttributes
,
1036 PciIoSetBarAttributes
,
1042 InitializePciIoProtocol (
1043 NON_DISCOVERABLE_PCI_DEVICE
*Dev
1046 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Desc
;
1049 InitializeListHead (&Dev
->UncachedAllocationList
);
1051 Dev
->ConfigSpace
.Hdr
.VendorId
= PCI_ID_VENDOR_UNKNOWN
;
1052 Dev
->ConfigSpace
.Hdr
.DeviceId
= PCI_ID_DEVICE_DONTCARE
;
1054 // Copy protocol structure
1055 CopyMem(&Dev
->PciIo
, &PciIoTemplate
, sizeof PciIoTemplate
);
1057 if (Dev
->Device
->DmaType
== NonDiscoverableDeviceDmaTypeNonCoherent
) {
1058 Dev
->PciIo
.AllocateBuffer
= NonCoherentPciIoAllocateBuffer
;
1059 Dev
->PciIo
.FreeBuffer
= NonCoherentPciIoFreeBuffer
;
1060 Dev
->PciIo
.Map
= NonCoherentPciIoMap
;
1061 Dev
->PciIo
.Unmap
= NonCoherentPciIoUnmap
;
1064 if (CompareGuid (Dev
->Device
->Type
, &gEdkiiNonDiscoverableAhciDeviceGuid
)) {
1065 Dev
->ConfigSpace
.Hdr
.ClassCode
[0] = PCI_IF_MASS_STORAGE_AHCI
;
1066 Dev
->ConfigSpace
.Hdr
.ClassCode
[1] = PCI_CLASS_MASS_STORAGE_SATADPA
;
1067 Dev
->ConfigSpace
.Hdr
.ClassCode
[2] = PCI_CLASS_MASS_STORAGE
;
1069 } else if (CompareGuid (Dev
->Device
->Type
,
1070 &gEdkiiNonDiscoverableEhciDeviceGuid
)) {
1071 Dev
->ConfigSpace
.Hdr
.ClassCode
[0] = PCI_IF_EHCI
;
1072 Dev
->ConfigSpace
.Hdr
.ClassCode
[1] = PCI_CLASS_SERIAL_USB
;
1073 Dev
->ConfigSpace
.Hdr
.ClassCode
[2] = PCI_CLASS_SERIAL
;
1075 } else if (CompareGuid (Dev
->Device
->Type
,
1076 &gEdkiiNonDiscoverableNvmeDeviceGuid
)) {
1077 Dev
->ConfigSpace
.Hdr
.ClassCode
[0] = 0x2; // PCI_IF_NVMHCI
1078 Dev
->ConfigSpace
.Hdr
.ClassCode
[1] = 0x8; // PCI_CLASS_MASS_STORAGE_NVM
1079 Dev
->ConfigSpace
.Hdr
.ClassCode
[2] = PCI_CLASS_MASS_STORAGE
;
1081 } else if (CompareGuid (Dev
->Device
->Type
,
1082 &gEdkiiNonDiscoverableOhciDeviceGuid
)) {
1083 Dev
->ConfigSpace
.Hdr
.ClassCode
[0] = PCI_IF_OHCI
;
1084 Dev
->ConfigSpace
.Hdr
.ClassCode
[1] = PCI_CLASS_SERIAL_USB
;
1085 Dev
->ConfigSpace
.Hdr
.ClassCode
[2] = PCI_CLASS_SERIAL
;
1087 } else if (CompareGuid (Dev
->Device
->Type
,
1088 &gEdkiiNonDiscoverableSdhciDeviceGuid
)) {
1089 Dev
->ConfigSpace
.Hdr
.ClassCode
[0] = 0x0; // don't care
1090 Dev
->ConfigSpace
.Hdr
.ClassCode
[1] = PCI_SUBCLASS_SD_HOST_CONTROLLER
;
1091 Dev
->ConfigSpace
.Hdr
.ClassCode
[2] = PCI_CLASS_SYSTEM_PERIPHERAL
;
1093 } else if (CompareGuid (Dev
->Device
->Type
,
1094 &gEdkiiNonDiscoverableXhciDeviceGuid
)) {
1095 Dev
->ConfigSpace
.Hdr
.ClassCode
[0] = PCI_IF_XHCI
;
1096 Dev
->ConfigSpace
.Hdr
.ClassCode
[1] = PCI_CLASS_SERIAL_USB
;
1097 Dev
->ConfigSpace
.Hdr
.ClassCode
[2] = PCI_CLASS_SERIAL
;
1099 } else if (CompareGuid (Dev
->Device
->Type
,
1100 &gEdkiiNonDiscoverableUhciDeviceGuid
)) {
1101 Dev
->ConfigSpace
.Hdr
.ClassCode
[0] = PCI_IF_UHCI
;
1102 Dev
->ConfigSpace
.Hdr
.ClassCode
[1] = PCI_CLASS_SERIAL_USB
;
1103 Dev
->ConfigSpace
.Hdr
.ClassCode
[2] = PCI_CLASS_SERIAL
;
1105 } else if (CompareGuid (Dev
->Device
->Type
,
1106 &gEdkiiNonDiscoverableUfsDeviceGuid
)) {
1107 Dev
->ConfigSpace
.Hdr
.ClassCode
[0] = 0x0; // don't care
1108 Dev
->ConfigSpace
.Hdr
.ClassCode
[1] = 0x9; // UFS controller subclass;
1109 Dev
->ConfigSpace
.Hdr
.ClassCode
[2] = PCI_CLASS_MASS_STORAGE
;
1112 ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER
);
1116 // Iterate over the resources to populate the virtual BARs
1118 Idx
= Dev
->BarOffset
;
1119 for (Desc
= Dev
->Device
->Resources
, Dev
->BarCount
= 0;
1120 Desc
->Desc
!= ACPI_END_TAG_DESCRIPTOR
;
1121 Desc
= (VOID
*)((UINT8
*)Desc
+ Desc
->Len
+ 3)) {
1123 ASSERT (Desc
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
);
1124 ASSERT (Desc
->ResType
== ACPI_ADDRESS_SPACE_TYPE_MEM
);
1126 if (Idx
>= PCI_MAX_BARS
||
1127 (Idx
== PCI_MAX_BARS
- 1 && Desc
->AddrSpaceGranularity
== 64)) {
1128 DEBUG ((DEBUG_ERROR
,
1129 "%a: resource count exceeds number of emulated BARs\n",
1135 Dev
->ConfigSpace
.Device
.Bar
[Idx
] = (UINT32
)Desc
->AddrRangeMin
;
1138 if (Desc
->AddrSpaceGranularity
== 64) {
1139 Dev
->ConfigSpace
.Device
.Bar
[Idx
] |= 0x4;
1140 Dev
->ConfigSpace
.Device
.Bar
[++Idx
] = (UINT32
)RShiftU64 (
1141 Desc
->AddrRangeMin
, 32);