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
);
563 // Find the uncached allocation list entry associated
564 // with this allocation
566 for (Entry
= Dev
->UncachedAllocationList
.ForwardLink
;
567 Entry
!= &Dev
->UncachedAllocationList
;
568 Entry
= Entry
->ForwardLink
) {
570 Alloc
= BASE_CR (Entry
, NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION
, List
);
571 if (Alloc
->HostAddress
== HostAddress
&& Alloc
->NumPages
== Pages
) {
573 // We are freeing the exact allocation we were given
574 // before by AllocateBuffer()
582 ASSERT_EFI_ERROR (EFI_NOT_FOUND
);
583 return EFI_NOT_FOUND
;
586 RemoveEntryList (&Alloc
->List
);
588 Status
= gDS
->SetMemorySpaceAttributes (
589 (EFI_PHYSICAL_ADDRESS
)(UINTN
)HostAddress
,
590 EFI_PAGES_TO_SIZE (Pages
),
592 if (EFI_ERROR (Status
)) {
597 // If we fail to restore the original attributes, it is better to leak the
598 // memory than to return it to the heap
600 FreePages (HostAddress
, Pages
);
610 NonCoherentPciIoAllocateBuffer (
611 IN EFI_PCI_IO_PROTOCOL
*This
,
612 IN EFI_ALLOCATE_TYPE Type
,
613 IN EFI_MEMORY_TYPE MemoryType
,
615 OUT VOID
**HostAddress
,
619 NON_DISCOVERABLE_PCI_DEVICE
*Dev
;
620 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor
;
623 NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION
*Alloc
;
626 Dev
= NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This
);
628 Status
= CoherentPciIoAllocateBuffer (This
, Type
, MemoryType
, Pages
,
629 &AllocAddress
, Attributes
);
630 if (EFI_ERROR (Status
)) {
634 Status
= gDS
->GetMemorySpaceDescriptor (
635 (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocAddress
,
637 if (EFI_ERROR (Status
)) {
641 if ((GcdDescriptor
.Capabilities
& (EFI_MEMORY_WC
| EFI_MEMORY_UC
)) == 0) {
642 Status
= EFI_UNSUPPORTED
;
647 // Set the preferred memory attributes
649 if ((Attributes
& EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE
) != 0 ||
650 (GcdDescriptor
.Capabilities
& EFI_MEMORY_UC
) == 0) {
652 // Use write combining if it was requested, or if it is the only
653 // type supported by the region.
655 MemType
= EFI_MEMORY_WC
;
657 MemType
= EFI_MEMORY_UC
;
660 Alloc
= AllocatePool (sizeof *Alloc
);
665 Alloc
->HostAddress
= AllocAddress
;
666 Alloc
->NumPages
= Pages
;
667 Alloc
->Attributes
= GcdDescriptor
.Attributes
;
670 // Record this allocation in the linked list, so we
671 // can restore the memory space attributes later
673 InsertHeadList (&Dev
->UncachedAllocationList
, &Alloc
->List
);
675 Status
= gDS
->SetMemorySpaceAttributes (
676 (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocAddress
,
677 EFI_PAGES_TO_SIZE (Pages
),
679 if (EFI_ERROR (Status
)) {
683 Status
= mCpu
->FlushDataCache (
685 (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocAddress
,
686 EFI_PAGES_TO_SIZE (Pages
),
687 EfiCpuFlushTypeInvalidate
);
688 if (EFI_ERROR (Status
)) {
692 *HostAddress
= AllocAddress
;
697 RemoveEntryList (&Alloc
->List
);
701 CoherentPciIoFreeBuffer (This
, Pages
, AllocAddress
);
708 NonCoherentPciIoMap (
709 IN EFI_PCI_IO_PROTOCOL
*This
,
710 IN EFI_PCI_IO_PROTOCOL_OPERATION Operation
,
711 IN VOID
*HostAddress
,
712 IN OUT UINTN
*NumberOfBytes
,
713 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
717 NON_DISCOVERABLE_PCI_DEVICE
*Dev
;
719 NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO
*MapInfo
;
722 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor
;
725 MapInfo
= AllocatePool (sizeof *MapInfo
);
726 if (MapInfo
== NULL
) {
727 return EFI_OUT_OF_RESOURCES
;
730 MapInfo
->HostAddress
= HostAddress
;
731 MapInfo
->Operation
= Operation
;
732 MapInfo
->NumberOfBytes
= *NumberOfBytes
;
734 Dev
= NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This
);
737 // If this device does not support 64-bit DMA addressing, we need to allocate
738 // a bounce buffer and copy over the data in case HostAddress >= 4 GB.
740 Bounce
= ((Dev
->Attributes
& EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
) == 0 &&
741 (UINTN
)HostAddress
+ *NumberOfBytes
> SIZE_4GB
);
745 case EfiPciIoOperationBusMasterRead
:
746 case EfiPciIoOperationBusMasterWrite
:
748 // For streaming DMA, it is sufficient if the buffer is aligned to
749 // the CPUs DMA buffer alignment.
751 AlignMask
= mCpu
->DmaBufferAlignment
- 1;
752 if ((((UINTN
) HostAddress
| *NumberOfBytes
) & AlignMask
) == 0) {
757 case EfiPciIoOperationBusMasterCommonBuffer
:
759 // Check whether the host address refers to an uncached mapping.
761 Status
= gDS
->GetMemorySpaceDescriptor (
762 (EFI_PHYSICAL_ADDRESS
)(UINTN
)HostAddress
,
764 if (EFI_ERROR (Status
) ||
765 (GcdDescriptor
.Attributes
& (EFI_MEMORY_WB
|EFI_MEMORY_WT
)) != 0) {
776 if (Operation
== EfiPciIoOperationBusMasterCommonBuffer
) {
777 Status
= EFI_DEVICE_ERROR
;
781 Status
= NonCoherentPciIoAllocateBuffer (This
, AllocateAnyPages
,
782 EfiBootServicesData
, EFI_SIZE_TO_PAGES (MapInfo
->NumberOfBytes
),
783 &AllocAddress
, EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE
);
784 if (EFI_ERROR (Status
)) {
787 MapInfo
->AllocAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocAddress
;
788 if (Operation
== EfiPciIoOperationBusMasterRead
) {
789 gBS
->CopyMem (AllocAddress
, HostAddress
, *NumberOfBytes
);
791 *DeviceAddress
= MapInfo
->AllocAddress
;
793 MapInfo
->AllocAddress
= 0;
794 *DeviceAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)HostAddress
;
797 // We are not using a bounce buffer: the mapping is sufficiently
798 // aligned to allow us to simply flush the caches. Note that cleaning
799 // the caches is necessary for both data directions:
800 // - for bus master read, we want the latest data to be present
802 // - for bus master write, we don't want any stale dirty cachelines that
803 // may be written back unexpectedly, and clobber the data written to
804 // main memory by the device.
806 mCpu
->FlushDataCache (mCpu
, (EFI_PHYSICAL_ADDRESS
)(UINTN
)HostAddress
,
807 *NumberOfBytes
, EfiCpuFlushTypeWriteBack
);
822 NonCoherentPciIoUnmap (
823 IN EFI_PCI_IO_PROTOCOL
*This
,
827 NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO
*MapInfo
;
829 if (Mapping
== NULL
) {
830 return EFI_DEVICE_ERROR
;
834 if (MapInfo
->AllocAddress
!= 0) {
836 // We are using a bounce buffer: copy back the data if necessary,
837 // and free the buffer.
839 if (MapInfo
->Operation
== EfiPciIoOperationBusMasterWrite
) {
840 gBS
->CopyMem (MapInfo
->HostAddress
, (VOID
*)(UINTN
)MapInfo
->AllocAddress
,
841 MapInfo
->NumberOfBytes
);
843 NonCoherentPciIoFreeBuffer (This
,
844 EFI_SIZE_TO_PAGES (MapInfo
->NumberOfBytes
),
845 (VOID
*)(UINTN
)MapInfo
->AllocAddress
);
848 // We are *not* using a bounce buffer: if this is a bus master write,
849 // we have to invalidate the caches so the CPU will see the uncached
850 // data written by the device.
852 if (MapInfo
->Operation
== EfiPciIoOperationBusMasterWrite
) {
853 mCpu
->FlushDataCache (mCpu
,
854 (EFI_PHYSICAL_ADDRESS
)(UINTN
)MapInfo
->HostAddress
,
855 MapInfo
->NumberOfBytes
, EfiCpuFlushTypeInvalidate
);
866 IN EFI_PCI_IO_PROTOCOL
*This
876 IN EFI_PCI_IO_PROTOCOL
*This
,
877 OUT UINTN
*SegmentNumber
,
878 OUT UINTN
*BusNumber
,
879 OUT UINTN
*DeviceNumber
,
880 OUT UINTN
*FunctionNumber
883 if (SegmentNumber
== NULL
||
885 DeviceNumber
== NULL
||
886 FunctionNumber
== NULL
) {
887 return EFI_INVALID_PARAMETER
;
902 IN EFI_PCI_IO_PROTOCOL
*This
,
903 IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation
,
904 IN UINT64 Attributes
,
905 OUT UINT64
*Result OPTIONAL
908 NON_DISCOVERABLE_PCI_DEVICE
*Dev
;
911 Dev
= NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This
);
915 case EfiPciIoAttributeOperationGet
:
916 if (Result
== NULL
) {
917 return EFI_INVALID_PARAMETER
;
919 *Result
= Dev
->Attributes
;
922 case EfiPciIoAttributeOperationSupported
:
923 if (Result
== NULL
) {
924 return EFI_INVALID_PARAMETER
;
926 *Result
= EFI_PCI_DEVICE_ENABLE
| EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE
;
929 case EfiPciIoAttributeOperationEnable
:
930 Attributes
|= Dev
->Attributes
;
931 case EfiPciIoAttributeOperationSet
:
932 Enable
= ((~Dev
->Attributes
& Attributes
) & EFI_PCI_DEVICE_ENABLE
) != 0;
933 Dev
->Attributes
= Attributes
;
936 case EfiPciIoAttributeOperationDisable
:
937 Dev
->Attributes
&= ~Attributes
;
941 return EFI_INVALID_PARAMETER
;
945 // If we're setting any of the EFI_PCI_DEVICE_ENABLE bits, perform
946 // the device specific initialization now.
948 if (Enable
&& !Dev
->Enabled
&& Dev
->Device
->Initialize
!= NULL
) {
949 Dev
->Device
->Initialize (Dev
->Device
);
958 PciIoGetBarAttributes (
959 IN EFI_PCI_IO_PROTOCOL
*This
,
961 OUT UINT64
*Supports OPTIONAL
,
962 OUT VOID
**Resources OPTIONAL
965 NON_DISCOVERABLE_PCI_DEVICE
*Dev
;
966 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
, *BarDesc
;
967 EFI_ACPI_END_TAG_DESCRIPTOR
*End
;
970 if (Supports
== NULL
&& Resources
== NULL
) {
971 return EFI_INVALID_PARAMETER
;
974 Dev
= NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This
);
976 Status
= GetBarResource (Dev
, BarIndex
, &BarDesc
);
977 if (EFI_ERROR (Status
)) {
982 // Don't expose any configurable attributes for our emulated BAR
984 if (Supports
!= NULL
) {
988 if (Resources
!= NULL
) {
989 Descriptor
= AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
) +
990 sizeof (EFI_ACPI_END_TAG_DESCRIPTOR
));
991 if (Descriptor
== NULL
) {
992 return EFI_OUT_OF_RESOURCES
;
995 CopyMem (Descriptor
, BarDesc
, sizeof *Descriptor
);
997 End
= (EFI_ACPI_END_TAG_DESCRIPTOR
*) (Descriptor
+ 1);
998 End
->Desc
= ACPI_END_TAG_DESCRIPTOR
;
1001 *Resources
= Descriptor
;
1009 PciIoSetBarAttributes (
1010 IN EFI_PCI_IO_PROTOCOL
*This
,
1011 IN UINT64 Attributes
,
1013 IN OUT UINT64
*Offset
,
1014 IN OUT UINT64
*Length
1018 return EFI_UNSUPPORTED
;
1021 STATIC CONST EFI_PCI_IO_PROTOCOL PciIoTemplate
=
1025 { PciIoMemRead
, PciIoMemWrite
},
1026 { PciIoIoRead
, PciIoIoWrite
},
1027 { PciIoPciRead
, PciIoPciWrite
},
1031 CoherentPciIoAllocateBuffer
,
1032 CoherentPciIoFreeBuffer
,
1036 PciIoGetBarAttributes
,
1037 PciIoSetBarAttributes
,
1043 InitializePciIoProtocol (
1044 NON_DISCOVERABLE_PCI_DEVICE
*Dev
1047 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Desc
;
1050 InitializeListHead (&Dev
->UncachedAllocationList
);
1052 Dev
->ConfigSpace
.Hdr
.VendorId
= PCI_ID_VENDOR_UNKNOWN
;
1053 Dev
->ConfigSpace
.Hdr
.DeviceId
= PCI_ID_DEVICE_DONTCARE
;
1055 // Copy protocol structure
1056 CopyMem(&Dev
->PciIo
, &PciIoTemplate
, sizeof PciIoTemplate
);
1058 if (Dev
->Device
->DmaType
== NonDiscoverableDeviceDmaTypeNonCoherent
) {
1059 Dev
->PciIo
.AllocateBuffer
= NonCoherentPciIoAllocateBuffer
;
1060 Dev
->PciIo
.FreeBuffer
= NonCoherentPciIoFreeBuffer
;
1061 Dev
->PciIo
.Map
= NonCoherentPciIoMap
;
1062 Dev
->PciIo
.Unmap
= NonCoherentPciIoUnmap
;
1065 if (CompareGuid (Dev
->Device
->Type
, &gEdkiiNonDiscoverableAhciDeviceGuid
)) {
1066 Dev
->ConfigSpace
.Hdr
.ClassCode
[0] = PCI_IF_MASS_STORAGE_AHCI
;
1067 Dev
->ConfigSpace
.Hdr
.ClassCode
[1] = PCI_CLASS_MASS_STORAGE_SATADPA
;
1068 Dev
->ConfigSpace
.Hdr
.ClassCode
[2] = PCI_CLASS_MASS_STORAGE
;
1070 } else if (CompareGuid (Dev
->Device
->Type
,
1071 &gEdkiiNonDiscoverableEhciDeviceGuid
)) {
1072 Dev
->ConfigSpace
.Hdr
.ClassCode
[0] = PCI_IF_EHCI
;
1073 Dev
->ConfigSpace
.Hdr
.ClassCode
[1] = PCI_CLASS_SERIAL_USB
;
1074 Dev
->ConfigSpace
.Hdr
.ClassCode
[2] = PCI_CLASS_SERIAL
;
1076 } else if (CompareGuid (Dev
->Device
->Type
,
1077 &gEdkiiNonDiscoverableNvmeDeviceGuid
)) {
1078 Dev
->ConfigSpace
.Hdr
.ClassCode
[0] = 0x2; // PCI_IF_NVMHCI
1079 Dev
->ConfigSpace
.Hdr
.ClassCode
[1] = 0x8; // PCI_CLASS_MASS_STORAGE_NVM
1080 Dev
->ConfigSpace
.Hdr
.ClassCode
[2] = PCI_CLASS_MASS_STORAGE
;
1082 } else if (CompareGuid (Dev
->Device
->Type
,
1083 &gEdkiiNonDiscoverableOhciDeviceGuid
)) {
1084 Dev
->ConfigSpace
.Hdr
.ClassCode
[0] = PCI_IF_OHCI
;
1085 Dev
->ConfigSpace
.Hdr
.ClassCode
[1] = PCI_CLASS_SERIAL_USB
;
1086 Dev
->ConfigSpace
.Hdr
.ClassCode
[2] = PCI_CLASS_SERIAL
;
1088 } else if (CompareGuid (Dev
->Device
->Type
,
1089 &gEdkiiNonDiscoverableSdhciDeviceGuid
)) {
1090 Dev
->ConfigSpace
.Hdr
.ClassCode
[0] = 0x0; // don't care
1091 Dev
->ConfigSpace
.Hdr
.ClassCode
[1] = PCI_SUBCLASS_SD_HOST_CONTROLLER
;
1092 Dev
->ConfigSpace
.Hdr
.ClassCode
[2] = PCI_CLASS_SYSTEM_PERIPHERAL
;
1094 } else if (CompareGuid (Dev
->Device
->Type
,
1095 &gEdkiiNonDiscoverableXhciDeviceGuid
)) {
1096 Dev
->ConfigSpace
.Hdr
.ClassCode
[0] = PCI_IF_XHCI
;
1097 Dev
->ConfigSpace
.Hdr
.ClassCode
[1] = PCI_CLASS_SERIAL_USB
;
1098 Dev
->ConfigSpace
.Hdr
.ClassCode
[2] = PCI_CLASS_SERIAL
;
1100 } else if (CompareGuid (Dev
->Device
->Type
,
1101 &gEdkiiNonDiscoverableUhciDeviceGuid
)) {
1102 Dev
->ConfigSpace
.Hdr
.ClassCode
[0] = PCI_IF_UHCI
;
1103 Dev
->ConfigSpace
.Hdr
.ClassCode
[1] = PCI_CLASS_SERIAL_USB
;
1104 Dev
->ConfigSpace
.Hdr
.ClassCode
[2] = PCI_CLASS_SERIAL
;
1106 } else if (CompareGuid (Dev
->Device
->Type
,
1107 &gEdkiiNonDiscoverableUfsDeviceGuid
)) {
1108 Dev
->ConfigSpace
.Hdr
.ClassCode
[0] = 0x0; // don't care
1109 Dev
->ConfigSpace
.Hdr
.ClassCode
[1] = 0x9; // UFS controller subclass;
1110 Dev
->ConfigSpace
.Hdr
.ClassCode
[2] = PCI_CLASS_MASS_STORAGE
;
1113 ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER
);
1117 // Iterate over the resources to populate the virtual BARs
1119 Idx
= Dev
->BarOffset
;
1120 for (Desc
= Dev
->Device
->Resources
, Dev
->BarCount
= 0;
1121 Desc
->Desc
!= ACPI_END_TAG_DESCRIPTOR
;
1122 Desc
= (VOID
*)((UINT8
*)Desc
+ Desc
->Len
+ 3)) {
1124 ASSERT (Desc
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
);
1125 ASSERT (Desc
->ResType
== ACPI_ADDRESS_SPACE_TYPE_MEM
);
1127 if (Idx
>= PCI_MAX_BARS
||
1128 (Idx
== PCI_MAX_BARS
- 1 && Desc
->AddrSpaceGranularity
== 64)) {
1129 DEBUG ((DEBUG_ERROR
,
1130 "%a: resource count exceeds number of emulated BARs\n",
1136 Dev
->ConfigSpace
.Device
.Bar
[Idx
] = (UINT32
)Desc
->AddrRangeMin
;
1139 if (Desc
->AddrSpaceGranularity
== 64) {
1140 Dev
->ConfigSpace
.Device
.Bar
[Idx
] |= 0x4;
1141 Dev
->ConfigSpace
.Device
.Bar
[++Idx
] = (UINT32
)RShiftU64 (
1142 Desc
->AddrRangeMin
, 32);