3 Copyright (c) 2006 - 2008, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 EFI PC-AT PCI Device IO driver
21 #include "PcatPciRootBridge.h"
27 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
,
28 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
30 IN UINT16 SubordinateBus
36 Initialize and install a Device IO protocol on a empty device path handle.
40 Handle - Handle of PCI RootBridge IO instance
41 PciRootBridgeIo - PCI RootBridge IO instance
42 DevicePath - Device Path of PCI RootBridge IO instance
43 PrimaryBus - Primary Bus
44 SubordinateBus - Subordinate Bus
48 EFI_SUCCESS - This driver is added to ControllerHandle.
49 EFI_ALREADY_STARTED - This driver is already running on ControllerHandle.
50 Others - This driver does not support this device.
55 DEVICE_IO_PRIVATE_DATA
*Private
;
58 // Initialize the Device IO device instance.
60 Private
= AllocateZeroPool (sizeof (DEVICE_IO_PRIVATE_DATA
));
61 if (Private
== NULL
) {
62 return EFI_OUT_OF_RESOURCES
;
65 Private
->Signature
= DEVICE_IO_PRIVATE_DATA_SIGNATURE
;
66 Private
->Handle
= Handle
;
67 Private
->PciRootBridgeIo
= PciRootBridgeIo
;
68 Private
->DevicePath
= DevicePath
;
69 Private
->PrimaryBus
= PrimaryBus
;
70 Private
->SubordinateBus
= SubordinateBus
;
72 Private
->DeviceIo
.Mem
.Read
= DeviceIoMemRead
;
73 Private
->DeviceIo
.Mem
.Write
= DeviceIoMemWrite
;
74 Private
->DeviceIo
.Io
.Read
= DeviceIoIoRead
;
75 Private
->DeviceIo
.Io
.Write
= DeviceIoIoWrite
;
76 Private
->DeviceIo
.Pci
.Read
= DeviceIoPciRead
;
77 Private
->DeviceIo
.Pci
.Write
= DeviceIoPciWrite
;
78 Private
->DeviceIo
.PciDevicePath
= DeviceIoPciDevicePath
;
79 Private
->DeviceIo
.Map
= DeviceIoMap
;
80 Private
->DeviceIo
.Unmap
= DeviceIoUnmap
;
81 Private
->DeviceIo
.AllocateBuffer
= DeviceIoAllocateBuffer
;
82 Private
->DeviceIo
.Flush
= DeviceIoFlush
;
83 Private
->DeviceIo
.FreeBuffer
= DeviceIoFreeBuffer
;
86 // Install protocol interfaces for the Device IO device.
88 Status
= gBS
->InstallMultipleProtocolInterfaces (
90 &gEfiDeviceIoProtocolGuid
,
94 ASSERT_EFI_ERROR (Status
);
102 IN EFI_DEVICE_IO_PROTOCOL
*This
,
103 IN EFI_IO_WIDTH Width
,
112 Perform reading memory mapped I/O space of device.
116 This - A pointer to EFI_DEVICE_IO protocol instance.
117 Width - Width of I/O operations.
118 Address - The base address of I/O operations.
119 Count - The number of I/O operations to perform.
120 Bytes moves is Width size * Count, starting at Address.
121 Buffer - The destination buffer to store results.
125 EFI_SUCCESS - The data was read from the device.
126 EFI_INVALID_PARAMETER - Width is invalid.
127 EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources.
132 DEVICE_IO_PRIVATE_DATA
*Private
;
134 Private
= DEVICE_IO_PRIVATE_DATA_FROM_THIS (This
);
136 if (Width
> MMIO_COPY_UINT64
) {
137 return EFI_INVALID_PARAMETER
;
139 if (Width
>= MMIO_COPY_UINT8
) {
140 Width
= (EFI_IO_WIDTH
) (Width
- MMIO_COPY_UINT8
);
141 Status
= Private
->PciRootBridgeIo
->CopyMem (
142 Private
->PciRootBridgeIo
,
143 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) Width
,
144 (UINT64
)(UINTN
) Buffer
,
149 Status
= Private
->PciRootBridgeIo
->Mem
.Read (
150 Private
->PciRootBridgeIo
,
151 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) Width
,
166 IN EFI_DEVICE_IO_PROTOCOL
*This
,
167 IN EFI_IO_WIDTH Width
,
176 Perform writing memory mapped I/O space of device.
180 This - A pointer to EFI_DEVICE_IO protocol instance.
181 Width - Width of I/O operations.
182 Address - The base address of I/O operations.
183 Count - The number of I/O operations to perform.
184 Bytes moves is Width size * Count, starting at Address.
185 Buffer - The source buffer of data to be written.
189 EFI_SUCCESS - The data was written to the device.
190 EFI_INVALID_PARAMETER - Width is invalid.
191 EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources.
196 DEVICE_IO_PRIVATE_DATA
*Private
;
198 Private
= DEVICE_IO_PRIVATE_DATA_FROM_THIS (This
);
200 if (Width
> MMIO_COPY_UINT64
) {
201 return EFI_INVALID_PARAMETER
;
203 if (Width
>= MMIO_COPY_UINT8
) {
204 Width
= (EFI_IO_WIDTH
) (Width
- MMIO_COPY_UINT8
);
205 Status
= Private
->PciRootBridgeIo
->CopyMem (
206 Private
->PciRootBridgeIo
,
207 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) Width
,
209 (UINT64
)(UINTN
) Buffer
,
213 Status
= Private
->PciRootBridgeIo
->Mem
.Write (
214 Private
->PciRootBridgeIo
,
215 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) Width
,
228 IN EFI_DEVICE_IO_PROTOCOL
*This
,
229 IN EFI_IO_WIDTH Width
,
238 Perform reading I/O space of device.
242 This - A pointer to EFI_DEVICE_IO protocol instance.
243 Width - Width of I/O operations.
244 Address - The base address of I/O operations.
245 Count - The number of I/O operations to perform.
246 Bytes moves is Width size * Count, starting at Address.
247 Buffer - The destination buffer to store results.
251 EFI_SUCCESS - The data was read from the device.
252 EFI_INVALID_PARAMETER - Width is invalid.
253 EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources.
258 DEVICE_IO_PRIVATE_DATA
*Private
;
260 Private
= DEVICE_IO_PRIVATE_DATA_FROM_THIS (This
);
262 if (Width
>= MMIO_COPY_UINT8
) {
263 return EFI_INVALID_PARAMETER
;
266 Status
= Private
->PciRootBridgeIo
->Io
.Read (
267 Private
->PciRootBridgeIo
,
268 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) Width
,
280 IN EFI_DEVICE_IO_PROTOCOL
*This
,
281 IN EFI_IO_WIDTH Width
,
290 Perform writing I/O space of device.
294 This - A pointer to EFI_DEVICE_IO protocol instance.
295 Width - Width of I/O operations.
296 Address - The base address of I/O operations.
297 Count - The number of I/O operations to perform.
298 Bytes moves is Width size * Count, starting at Address.
299 Buffer - The source buffer of data to be written.
303 EFI_SUCCESS - The data was written to the device.
304 EFI_INVALID_PARAMETER - Width is invalid.
305 EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources.
310 DEVICE_IO_PRIVATE_DATA
*Private
;
312 Private
= DEVICE_IO_PRIVATE_DATA_FROM_THIS (This
);
314 if (Width
>= MMIO_COPY_UINT8
) {
315 return EFI_INVALID_PARAMETER
;
318 Status
= Private
->PciRootBridgeIo
->Io
.Write (
319 Private
->PciRootBridgeIo
,
320 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) Width
,
332 IN EFI_DEVICE_IO_PROTOCOL
*This
,
333 IN EFI_IO_WIDTH Width
,
342 Perform reading PCI configuration space of device
346 This - A pointer to EFI_DEVICE_IO protocol instance.
347 Width - Width of I/O operations.
348 Address - The base address of I/O operations.
349 Count - The number of I/O operations to perform.
350 Bytes moves is Width size * Count, starting at Address.
351 Buffer - The destination buffer to store results.
355 EFI_SUCCESS - The data was read from the device.
356 EFI_INVALID_PARAMETER - Width is invalid.
357 EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources.
362 DEVICE_IO_PRIVATE_DATA
*Private
;
364 Private
= DEVICE_IO_PRIVATE_DATA_FROM_THIS (This
);
366 if (Width
< 0 || Width
>= MMIO_COPY_UINT8
) {
367 return EFI_INVALID_PARAMETER
;
370 Status
= Private
->PciRootBridgeIo
->Pci
.Read (
371 Private
->PciRootBridgeIo
,
372 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) Width
,
384 IN EFI_DEVICE_IO_PROTOCOL
*This
,
385 IN EFI_IO_WIDTH Width
,
394 Perform writing PCI configuration space of device.
398 This - A pointer to EFI_DEVICE_IO protocol instance.
399 Width - Width of I/O operations.
400 Address - The base address of I/O operations.
401 Count - The number of I/O operations to perform.
402 Bytes moves is Width size * Count, starting at Address.
403 Buffer - The source buffer of data to be written.
407 EFI_SUCCESS - The data was written to the device.
408 EFI_INVALID_PARAMETER - Width is invalid.
409 EFI_OUT_OF_RESOURCES - The request could not be completed due to lack of resources.
414 DEVICE_IO_PRIVATE_DATA
*Private
;
416 Private
= DEVICE_IO_PRIVATE_DATA_FROM_THIS (This
);
418 if (Width
< 0 || Width
>= MMIO_COPY_UINT8
) {
419 return EFI_INVALID_PARAMETER
;
422 Status
= Private
->PciRootBridgeIo
->Pci
.Write (
423 Private
->PciRootBridgeIo
,
424 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) Width
,
433 EFI_DEVICE_PATH_PROTOCOL
*
434 AppendPciDevicePath (
435 IN DEVICE_IO_PRIVATE_DATA
*Private
,
439 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
440 IN OUT UINT16
*BridgePrimaryBus
,
441 IN OUT UINT16
*BridgeSubordinateBus
447 Append a PCI device path node to another device path.
451 Private - A pointer to DEVICE_IO_PRIVATE_DATA instance.
452 Bus - PCI bus number of the device.
453 Device - PCI device number of the device.
454 Function - PCI function number of the device.
455 DevicePath - Original device path which will be appended a PCI device path node.
456 BridgePrimaryBus - Primary bus number of the bridge.
457 BridgeSubordinateBus - Subordinate bus number of the bridge.
461 Pointer to the appended PCI device path.
469 PCI_TYPE01 PciBridge
;
471 EFI_DEVICE_PATH_PROTOCOL
*ReturnDevicePath
;
472 PCI_DEVICE_PATH PciNode
;
475 for (ThisBus
= *BridgePrimaryBus
; ThisBus
<= *BridgeSubordinateBus
; ThisBus
++) {
476 for (ThisDevice
= 0; ThisDevice
<= PCI_MAX_DEVICE
; ThisDevice
++) {
477 for (ThisFunc
= 0; ThisFunc
<= PCI_MAX_FUNC
; ThisFunc
++) {
478 Address
= EFI_PCI_ADDRESS (ThisBus
, ThisDevice
, ThisFunc
, 0);
479 ZeroMem (PciPtr
, sizeof (PCI_TYPE01
));
480 Private
->DeviceIo
.Pci
.Read (
485 &(PciPtr
->Hdr
.VendorId
)
487 if ((PciPtr
->Hdr
.VendorId
== 0xffff) && (ThisFunc
== 0)) {
490 if (PciPtr
->Hdr
.VendorId
== 0xffff) {
494 Private
->DeviceIo
.Pci
.Read (
498 sizeof (PCI_TYPE01
) / sizeof (UINT32
),
501 if (IS_PCI_BRIDGE (PciPtr
)) {
502 if (Bus
>= PciPtr
->Bridge
.SecondaryBus
&& Bus
<= PciPtr
->Bridge
.SubordinateBus
) {
504 PciNode
.Header
.Type
= HARDWARE_DEVICE_PATH
;
505 PciNode
.Header
.SubType
= HW_PCI_DP
;
506 SetDevicePathNodeLength (&PciNode
.Header
, sizeof (PciNode
));
508 PciNode
.Device
= ThisDevice
;
509 PciNode
.Function
= ThisFunc
;
510 ReturnDevicePath
= AppendDevicePathNode (DevicePath
, &PciNode
.Header
);
512 *BridgePrimaryBus
= PciPtr
->Bridge
.SecondaryBus
;
513 *BridgeSubordinateBus
= PciPtr
->Bridge
.SubordinateBus
;
514 return ReturnDevicePath
;
518 if ((ThisFunc
== 0) && ((PciPtr
->Hdr
.HeaderType
& HEADER_TYPE_MULTI_FUNCTION
) == 0x0)) {
520 // Skip sub functions, this is not a multi function device
528 ZeroMem (&PciNode
, sizeof (PciNode
));
529 PciNode
.Header
.Type
= HARDWARE_DEVICE_PATH
;
530 PciNode
.Header
.SubType
= HW_PCI_DP
;
531 SetDevicePathNodeLength (&PciNode
.Header
, sizeof (PciNode
));
532 PciNode
.Device
= Device
;
533 PciNode
.Function
= Function
;
535 ReturnDevicePath
= AppendDevicePathNode (DevicePath
, &PciNode
.Header
);
537 *BridgePrimaryBus
= 0xffff;
538 *BridgeSubordinateBus
= 0xffff;
539 return ReturnDevicePath
;
544 DeviceIoPciDevicePath (
545 IN EFI_DEVICE_IO_PROTOCOL
*This
,
547 IN OUT EFI_DEVICE_PATH_PROTOCOL
**PciDevicePath
553 Provides an EFI Device Path for a PCI device with the given PCI configuration space address.
557 This - A pointer to the EFI_DEVICE_IO_INTERFACE instance.
558 Address - The PCI configuration space address of the device whose Device Path
559 is going to be returned.
560 PciDevicePath - A pointer to the pointer for the EFI Device Path for PciAddress.
561 Memory for the Device Path is allocated from the pool.
565 EFI_SUCCESS - The PciDevicePath returns a pointer to a valid EFI Device Path.
566 EFI_UNSUPPORTED - The PciAddress does not map to a valid EFI Device Path.
567 EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.
571 DEVICE_IO_PRIVATE_DATA
*Private
;
573 UINT16 SubordinateBus
;
578 Private
= DEVICE_IO_PRIVATE_DATA_FROM_THIS (This
);
580 Bus
= (UINT8
) (((UINT32
) Address
>> 24) & 0xff);
581 Device
= (UINT8
) (((UINT32
) Address
>> 16) & 0xff);
582 Func
= (UINT8
) (((UINT32
) Address
>> 8) & 0xff);
584 if (Bus
< Private
->PrimaryBus
|| Bus
> Private
->SubordinateBus
) {
585 return EFI_UNSUPPORTED
;
588 *PciDevicePath
= Private
->DevicePath
;
589 PrimaryBus
= Private
->PrimaryBus
;
590 SubordinateBus
= Private
->SubordinateBus
;
592 *PciDevicePath
= AppendPciDevicePath (
601 if (*PciDevicePath
== NULL
) {
602 return EFI_OUT_OF_RESOURCES
;
604 } while (PrimaryBus
!= 0xffff);
612 IN EFI_DEVICE_IO_PROTOCOL
*This
,
613 IN EFI_IO_OPERATION_TYPE Operation
,
614 IN EFI_PHYSICAL_ADDRESS
*HostAddress
,
615 IN OUT UINTN
*NumberOfBytes
,
616 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
623 Provides the device-specific addresses needed to access system memory.
627 This - A pointer to the EFI_DEVICE_IO_INTERFACE instance.
628 Operation - Indicates if the bus master is going to read or write to system memory.
629 HostAddress - The system memory address to map to the device.
630 NumberOfBytes - On input the number of bytes to map. On output the number of bytes
632 DeviceAddress - The resulting map address for the bus master device to use to access the
634 Mapping - A resulting value to pass to Unmap().
638 EFI_SUCCESS - The range was mapped for the returned NumberOfBytes.
639 EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined.
640 EFI_UNSUPPORTED - The HostAddress cannot be mapped as a common buffer.
641 EFI_DEVICE_ERROR - The system hardware could not map the requested address.
642 EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.
647 DEVICE_IO_PRIVATE_DATA
*Private
;
649 Private
= DEVICE_IO_PRIVATE_DATA_FROM_THIS (This
);
651 if (Operation
< 0 || Operation
> EfiBusMasterCommonBuffer
) {
652 return EFI_INVALID_PARAMETER
;
655 if (((UINTN
) (*HostAddress
) != (*HostAddress
)) && Operation
== EfiBusMasterCommonBuffer
) {
656 return EFI_UNSUPPORTED
;
659 Status
= Private
->PciRootBridgeIo
->Map (
660 Private
->PciRootBridgeIo
,
661 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION
) Operation
,
662 (VOID
*) (UINTN
) (*HostAddress
),
674 IN EFI_DEVICE_IO_PROTOCOL
*This
,
681 Completes the Map() operation and releases any corresponding resources.
685 This - A pointer to the EFI_DEVICE_IO_INTERFACE instance.
686 Mapping - The mapping value returned from Map().
690 EFI_SUCCESS - The range was unmapped.
691 EFI_DEVICE_ERROR - The data was not committed to the target system memory.
696 DEVICE_IO_PRIVATE_DATA
*Private
;
698 Private
= DEVICE_IO_PRIVATE_DATA_FROM_THIS (This
);
700 Status
= Private
->PciRootBridgeIo
->Unmap (
701 Private
->PciRootBridgeIo
,
710 DeviceIoAllocateBuffer (
711 IN EFI_DEVICE_IO_PROTOCOL
*This
,
712 IN EFI_ALLOCATE_TYPE Type
,
713 IN EFI_MEMORY_TYPE MemoryType
,
715 IN OUT EFI_PHYSICAL_ADDRESS
*PhysicalAddress
721 Allocates pages that are suitable for an EFIBusMasterCommonBuffer mapping.
725 This - A pointer to the EFI_DEVICE_IO_INTERFACE instance.
726 Type - The type allocation to perform.
727 MemoryType - The type of memory to allocate, EfiBootServicesData or
728 EfiRuntimeServicesData.
729 Pages - The number of pages to allocate.
730 PhysicalAddress - A pointer to store the base address of the allocated range.
734 EFI_SUCCESS - The requested memory pages were allocated.
735 EFI_OUT_OF_RESOURCES - The memory pages could not be allocated.
736 EFI_INVALID_PARAMETER - The requested memory type is invalid.
737 EFI_UNSUPPORTED - The requested PhysicalAddress is not supported on
743 EFI_PHYSICAL_ADDRESS HostAddress
;
745 HostAddress
= *PhysicalAddress
;
747 if ((MemoryType
!= EfiBootServicesData
) && (MemoryType
!= EfiRuntimeServicesData
)) {
748 return EFI_INVALID_PARAMETER
;
751 if ((Type
>= MaxAllocateType
) || (Type
< AllocateAnyPages
)) {
752 return EFI_INVALID_PARAMETER
;
755 if ((Type
== AllocateAddress
) && (HostAddress
+ EFI_PAGES_TO_SIZE (Pages
) - 1 > MAX_COMMON_BUFFER
)) {
756 return EFI_UNSUPPORTED
;
759 if ((AllocateAnyPages
== Type
) || (AllocateMaxAddress
== Type
&& HostAddress
> MAX_COMMON_BUFFER
)) {
760 Type
= AllocateMaxAddress
;
761 HostAddress
= MAX_COMMON_BUFFER
;
764 Status
= gBS
->AllocatePages (
770 if (EFI_ERROR (Status
)) {
775 *PhysicalAddress
= HostAddress
;
783 IN EFI_DEVICE_IO_PROTOCOL
*This
789 Flushes any posted write data to the device.
793 This - A pointer to the EFI_DEVICE_IO_INTERFACE instance.
797 EFI_SUCCESS - The buffers were flushed.
798 EFI_DEVICE_ERROR - The buffers were not flushed due to a hardware error.
803 DEVICE_IO_PRIVATE_DATA
*Private
;
805 Private
= DEVICE_IO_PRIVATE_DATA_FROM_THIS (This
);
807 Status
= Private
->PciRootBridgeIo
->Flush (Private
->PciRootBridgeIo
);
815 IN EFI_DEVICE_IO_PROTOCOL
*This
,
817 IN EFI_PHYSICAL_ADDRESS HostAddress
823 Frees pages that were allocated with AllocateBuffer().
827 This - A pointer to the EFI_DEVICE_IO_INTERFACE instance.
828 Pages - The number of pages to free.
829 HostAddress - The base address of the range to free.
833 EFI_SUCCESS - The requested memory pages were freed.
834 EFI_NOT_FOUND - The requested memory pages were not allocated with
836 EFI_INVALID_PARAMETER - HostAddress is not page aligned or Pages is invalid.
840 if (((HostAddress
& EFI_PAGE_MASK
) != 0) || (Pages
<= 0)) {
841 return EFI_INVALID_PARAMETER
;
844 return gBS
->FreePages (HostAddress
, Pages
);