2 The implementation for EFI_ISA_IO_PROTOCOL.
4 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "InternalIsaIo.h"
20 EFI_ISA_IO_PROTOCOL mIsaIoInterface
= {
40 EFI_ISA_DMA_REGISTERS mDmaRegisters
[8] = {
65 }, // Channel 4 is invalid
84 Initializes an ISA I/O Instance
86 @param[in] IsaIoDevice The iso device to be initialized.
87 @param[in] IsaDeviceResourceList The resource list.
91 InitializeIsaIoInstance (
92 IN ISA_IO_DEVICE
*IsaIoDevice
,
93 IN EFI_ISA_ACPI_RESOURCE_LIST
*IsaDeviceResourceList
97 // Use the ISA IO Protocol structure template to initialize the ISA IO instance
102 sizeof (EFI_ISA_IO_PROTOCOL
)
105 IsaIoDevice
->IsaIo
.ResourceList
= IsaDeviceResourceList
;
109 Performs an ISA I/O Read Cycle
111 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
112 @param[in] Width Specifies the width of the I/O operation.
113 @param[in] Offset The offset in ISA I/O space to start the I/O operation.
114 @param[in] Count The number of I/O operations to perform.
115 @param[out] Buffer The destination buffer to store the results
117 @retval EFI_SUCCESS The data was read from the device sucessfully.
118 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
119 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
120 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
125 IN EFI_ISA_IO_PROTOCOL
*This
,
126 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
133 ISA_IO_DEVICE
*IsaIoDevice
;
135 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
138 // Verify Isa IO Access
140 Status
= IsaIoVerifyAccess (
147 if (EFI_ERROR (Status
)) {
151 Status
= IsaIoDevice
->PciIo
->Io
.Read (
153 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
154 EFI_PCI_IO_PASS_THROUGH_BAR
,
160 if (EFI_ERROR (Status
)) {
162 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
163 EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
171 Performs an ISA I/O Write Cycle
173 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
174 @param[in] Width Specifies the width of the I/O operation.
175 @param[in] Offset The offset in ISA I/O space to start the I/O operation.
176 @param[in] Count The number of I/O operations to perform.
177 @param[in] Buffer The source buffer to write data from
179 @retval EFI_SUCCESS The data was writen to the device sucessfully.
180 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
181 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
182 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
187 IN EFI_ISA_IO_PROTOCOL
*This
,
188 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
195 ISA_IO_DEVICE
*IsaIoDevice
;
197 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
200 // Verify Isa IO Access
202 Status
= IsaIoVerifyAccess (
209 if (EFI_ERROR (Status
)) {
213 Status
= IsaIoDevice
->PciIo
->Io
.Write (
215 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
216 EFI_PCI_IO_PASS_THROUGH_BAR
,
222 if (EFI_ERROR (Status
)) {
224 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
225 EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
233 Writes an 8-bit I/O Port
235 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
236 @param[in] Offset The offset in ISA IO space to start the IO operation.
237 @param[in] Value The data to write port.
239 @retval EFI_SUCCESS Success.
240 @retval EFI_INVALID_PARAMETER Parameter is invalid.
241 @retval EFI_UNSUPPORTED The address range specified by Offset is not valid.
242 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
246 IN EFI_ISA_IO_PROTOCOL
*This
,
252 ISA_IO_DEVICE
*IsaIoDevice
;
254 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
256 Status
= IsaIoDevice
->PciIo
->Io
.Write (
259 EFI_PCI_IO_PASS_THROUGH_BAR
,
264 if (EFI_ERROR (Status
)) {
266 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
267 EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
278 Writes I/O operation base address and count number to a 8 bit I/O Port.
280 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
281 @param[in] AddrOffset The address' offset.
282 @param[in] PageOffset The page's offest.
283 @param[in] CountOffset The count's offset.
284 @param[in] BaseAddress The base address.
285 @param[in] Count The number of I/O operations to perform.
287 @retval EFI_SUCCESS Success.
288 @retval EFI_INVALID_PARAMETER Parameter is invalid.
289 @retval EFI_UNSUPPORTED The address range specified by these Offsets and Count is not valid.
290 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
294 IN EFI_ISA_IO_PROTOCOL
*This
,
295 IN UINT32 AddrOffset
,
296 IN UINT32 PageOffset
,
297 IN UINT32 CountOffset
,
298 IN UINT32 BaseAddress
,
304 Status
= WritePort (This
, AddrOffset
, (UINT8
) (BaseAddress
& 0xff));
305 if (EFI_ERROR (Status
)) {
309 Status
= WritePort (This
, AddrOffset
, (UINT8
) ((BaseAddress
>> 8) & 0xff));
310 if (EFI_ERROR (Status
)) {
314 Status
= WritePort (This
, PageOffset
, (UINT8
) ((BaseAddress
>> 16) & 0xff));
315 if (EFI_ERROR (Status
)) {
319 Status
= WritePort (This
, CountOffset
, (UINT8
) (Count
& 0xff));
320 if (EFI_ERROR (Status
)) {
324 Status
= WritePort (This
, CountOffset
, (UINT8
) ((Count
>> 8) & 0xff));
329 Unmaps a memory region for DMA
331 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
332 @param[in] Mapping The mapping value returned from EFI_ISA_IO.Map().
334 @retval EFI_SUCCESS The range was unmapped.
335 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
340 IN EFI_ISA_IO_PROTOCOL
*This
,
344 ISA_MAP_INFO
*IsaMapInfo
;
347 // Check if DMA is supported.
349 if ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_SUPPORT_DMA
) == 0) {
350 return EFI_UNSUPPORTED
;
354 // See if the Map() operation associated with this Unmap() required a mapping
355 // buffer.If a mapping buffer was not required, then this function simply
356 // returns EFI_SUCCESS.
358 if (Mapping
!= NULL
) {
360 // Get the MAP_INFO structure from Mapping
362 IsaMapInfo
= (ISA_MAP_INFO
*) Mapping
;
365 // If this is a write operation from the Agent's point of view,
366 // then copy the contents of the mapped buffer into the real buffer
367 // so the processor can read the contents of the real buffer.
369 if (IsaMapInfo
->Operation
== EfiIsaIoOperationBusMasterWrite
) {
371 (VOID
*) (UINTN
) IsaMapInfo
->HostAddress
,
372 (VOID
*) (UINTN
) IsaMapInfo
->MappedHostAddress
,
373 IsaMapInfo
->NumberOfBytes
377 // Free the mapped buffer and the MAP_INFO structure.
379 gBS
->FreePages (IsaMapInfo
->MappedHostAddress
, IsaMapInfo
->NumberOfPages
);
380 FreePool (IsaMapInfo
);
387 Flushes any posted write data to the system memory.
389 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
391 @retval EFI_SUCCESS The buffers were flushed.
392 @retval EFI_DEVICE_ERROR The buffers were not flushed due to a hardware error.
397 IN EFI_ISA_IO_PROTOCOL
*This
401 ISA_IO_DEVICE
*IsaIoDevice
;
403 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
405 Status
= IsaIoDevice
->PciIo
->Flush (IsaIoDevice
->PciIo
);
407 if (EFI_ERROR (Status
)) {
409 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
410 EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
418 Verifies access to an ISA device
420 @param[in] IsaIoDevice The ISA device to be verified.
421 @param[in] Type The Access type. The input must be either IsaAccessTypeMem or IsaAccessTypeIo.
422 @param[in] Width The width of the memory operation.
423 @param[in] Count The number of memory operations to perform.
424 @param[in] Offset The offset in ISA memory space to start the memory operation.
426 @retval EFI_SUCCESS Verify success.
427 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
428 @retval EFI_UNSUPPORTED The device ont support the access type.
432 IN ISA_IO_DEVICE
*IsaIoDevice
,
433 IN ISA_ACCESS_TYPE Type
,
434 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
439 EFI_ISA_ACPI_RESOURCE
*Item
;
442 if (Width
< EfiIsaIoWidthUint8
||
443 Width
>= EfiIsaIoWidthMaximum
||
444 Width
== EfiIsaIoWidthReserved
||
445 Width
== EfiIsaIoWidthFifoReserved
||
446 Width
== EfiIsaIoWidthFillReserved
448 return EFI_INVALID_PARAMETER
;
452 // If Width is EfiIsaIoWidthFifoUintX then convert to EfiIsaIoWidthUintX
453 // If Width is EfiIsaIoWidthFillUintX then convert to EfiIsaIoWidthUintX
455 if (Width
>= EfiIsaIoWidthFifoUint8
&& Width
< EfiIsaIoWidthFifoReserved
) {
459 Width
= (EFI_ISA_IO_PROTOCOL_WIDTH
) (Width
& 0x03);
461 Status
= EFI_UNSUPPORTED
;
462 Item
= IsaIoDevice
->IsaIo
.ResourceList
->ResourceItem
;
463 while (Item
->Type
!= EfiIsaAcpiResourceEndOfList
) {
464 if ((Type
== IsaAccessTypeMem
&& Item
->Type
== EfiIsaAcpiResourceMemory
) ||
465 (Type
== IsaAccessTypeIo
&& Item
->Type
== EfiIsaAcpiResourceIo
)) {
466 if (Offset
>= Item
->StartRange
&& (Offset
+ Count
* (UINT32
)(1 << Width
)) - 1 <= Item
->EndRange
) {
470 if (Offset
>= Item
->StartRange
&& Offset
<= Item
->EndRange
) {
471 Status
= EFI_INVALID_PARAMETER
;
482 Performs an ISA Memory Read Cycle
484 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
485 @param[in] Width Specifies the width of the memory operation.
486 @param[in] Offset The offset in ISA memory space to start the memory operation.
487 @param[in] Count The number of memory operations to perform.
488 @param[out] Buffer The destination buffer to store the results
490 @retval EFI_SUCCESS The data was read from the device successfully.
491 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
492 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
493 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
498 IN EFI_ISA_IO_PROTOCOL
*This
,
499 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
506 ISA_IO_DEVICE
*IsaIoDevice
;
509 // Check if ISA memory is supported.
511 if ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY
) == 0) {
512 return EFI_UNSUPPORTED
;
515 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
518 // Verify the Isa Io Access
520 Status
= IsaIoVerifyAccess (
527 if (EFI_ERROR (Status
)) {
531 Status
= IsaIoDevice
->PciIo
->Mem
.Read (
533 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
534 EFI_PCI_IO_PASS_THROUGH_BAR
,
540 if (EFI_ERROR (Status
)) {
542 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
543 EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
551 Performs an ISA Memory Write Cycle
553 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
554 @param[in] Width Specifies the width of the memory operation.
555 @param[in] Offset The offset in ISA memory space to start the memory operation.
556 @param[in] Count The number of memory operations to perform.
557 @param[in] Buffer The source buffer to write data from
559 @retval EFI_SUCCESS The data was written to the device sucessfully.
560 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
561 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
562 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
567 IN EFI_ISA_IO_PROTOCOL
*This
,
568 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
575 ISA_IO_DEVICE
*IsaIoDevice
;
578 // Check if ISA memory is supported.
580 if ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY
) == 0) {
581 return EFI_UNSUPPORTED
;
584 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
587 // Verify Isa IO Access
589 Status
= IsaIoVerifyAccess (
596 if (EFI_ERROR (Status
)) {
600 Status
= IsaIoDevice
->PciIo
->Mem
.Write (
602 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
603 EFI_PCI_IO_PASS_THROUGH_BAR
,
609 if (EFI_ERROR (Status
)) {
611 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
612 EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
620 Copy one region of ISA memory space to another region of ISA memory space on the ISA controller.
622 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
623 @param[in] Width Specifies the width of the memory copy operation.
624 @param[in] DestOffset The offset of the destination
625 @param[in] SrcOffset The offset of the source
626 @param[in] Count The number of memory copy operations to perform
628 @retval EFI_SUCCESS The data was copied sucessfully.
629 @retval EFI_UNSUPPORTED The DestOffset or SrcOffset is not valid for this device.
630 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
631 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
636 IN EFI_ISA_IO_PROTOCOL
*This
,
637 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
638 IN UINT32 DestOffset
,
644 ISA_IO_DEVICE
*IsaIoDevice
;
647 // Check if ISA memory is supported.
649 if ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY
) == 0) {
650 return EFI_UNSUPPORTED
;
653 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
656 // Verify Isa IO Access for destination and source
658 Status
= IsaIoVerifyAccess (
665 if (EFI_ERROR (Status
)) {
669 Status
= IsaIoVerifyAccess (
676 if (EFI_ERROR (Status
)) {
680 Status
= IsaIoDevice
->PciIo
->CopyMem (
682 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
683 EFI_PCI_IO_PASS_THROUGH_BAR
,
685 EFI_PCI_IO_PASS_THROUGH_BAR
,
690 if (EFI_ERROR (Status
)) {
692 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
693 EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
701 Maps a memory region for DMA, note this implementation
702 only supports slave read/write operation to save code size.
704 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
705 @param Operation Indicates the type of DMA (slave or bus master), and if
706 the DMA operation is going to read or write to system memory.
707 @param ChannelNumber The slave channel number to use for this DMA operation.
708 If Operation and ChannelAttributes shows that this device
709 performs bus mastering DMA, then this field is ignored.
710 The legal range for this field is 0..7.
711 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
712 @param HostAddress The system memory address to map to the device.
713 @param NumberOfBytes On input the number of bytes to map. On output the number
714 of bytes that were mapped.
715 @param DeviceAddress The resulting map address for the bus master device to use
716 to access the hosts HostAddress.
717 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
719 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
720 @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.
721 @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.
722 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
723 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
726 IsaIoMapOnlySupportSlaveReadWrite (
727 IN EFI_ISA_IO_PROTOCOL
*This
,
728 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation
,
729 IN UINT8 ChannelNumber OPTIONAL
,
730 IN UINT32 ChannelAttributes
,
731 IN VOID
*HostAddress
,
732 IN OUT UINTN
*NumberOfBytes
,
733 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
738 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
739 ISA_MAP_INFO
*IsaMapInfo
;
741 UINTN MaxNumberOfBytes
;
746 UINT8 DmaChannelMode
;
748 if ((NULL
== This
) ||
749 (NULL
== HostAddress
) ||
750 (NULL
== NumberOfBytes
) ||
751 (NULL
== DeviceAddress
) ||
754 return EFI_INVALID_PARAMETER
;
758 // Initialize the return values to their defaults
763 // Make sure the Operation parameter is valid.
764 // Light IsaIo only supports two operations.
766 if (!(Operation
== EfiIsaIoOperationSlaveRead
||
767 Operation
== EfiIsaIoOperationSlaveWrite
)) {
768 return EFI_INVALID_PARAMETER
;
771 if (ChannelNumber
>= 4) {
773 // The Light IsaIo doesn't support channelNumber larger than 4.
775 return EFI_INVALID_PARAMETER
;
779 // Map the HostAddress to a DeviceAddress.
781 PhysicalAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
;
782 if ((PhysicalAddress
+ *NumberOfBytes
) > ISA_MAX_MEMORY_ADDRESS
) {
784 // Common Buffer operations can not be remapped. If the common buffer
785 // is above 16MB, then it is not possible to generate a mapping, so return
788 if (Operation
== EfiIsaIoOperationBusMasterCommonBuffer
) {
789 return EFI_UNSUPPORTED
;
792 // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
795 IsaMapInfo
= AllocatePool (sizeof (ISA_MAP_INFO
));
796 if (IsaMapInfo
== NULL
) {
798 return EFI_OUT_OF_RESOURCES
;
801 // Return a pointer to the MAP_INFO structure in Mapping
803 *Mapping
= IsaMapInfo
;
806 // Initialize the MAP_INFO structure
808 IsaMapInfo
->Operation
= Operation
;
809 IsaMapInfo
->NumberOfBytes
= *NumberOfBytes
;
810 IsaMapInfo
->NumberOfPages
= EFI_SIZE_TO_PAGES (*NumberOfBytes
);
811 IsaMapInfo
->HostAddress
= PhysicalAddress
;
812 IsaMapInfo
->MappedHostAddress
= ISA_MAX_MEMORY_ADDRESS
- 1;
815 // Allocate a buffer below 16MB to map the transfer to.
817 Status
= gBS
->AllocatePages (
820 IsaMapInfo
->NumberOfPages
,
821 &IsaMapInfo
->MappedHostAddress
823 if (EFI_ERROR (Status
)) {
824 FreePool (IsaMapInfo
);
830 // If this is a read operation from the DMA agents's point of view,
831 // then copy the contents of the real buffer into the mapped buffer
832 // so the DMA agent can read the contents of the real buffer.
834 if (Operation
== EfiIsaIoOperationSlaveRead
) {
836 (VOID
*) (UINTN
) IsaMapInfo
->MappedHostAddress
,
837 (VOID
*) (UINTN
) IsaMapInfo
->HostAddress
,
838 IsaMapInfo
->NumberOfBytes
842 // The DeviceAddress is the address of the maped buffer below 16 MB
844 *DeviceAddress
= IsaMapInfo
->MappedHostAddress
;
847 // The transfer is below 16 MB, so the DeviceAddress is simply the
850 *DeviceAddress
= PhysicalAddress
;
854 // Figure out what to program into the DMA Channel Mode Register
856 DmaMode
= (UINT8
) (B_8237_DMA_CHMODE_INCREMENT
| (ChannelNumber
& 0x03));
857 if (Operation
== EfiIsaIoOperationSlaveRead
) {
858 DmaMode
|= V_8237_DMA_CHMODE_MEM2IO
;
860 DmaMode
|= V_8237_DMA_CHMODE_IO2MEM
;
863 // We only support EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE in simplified IsaIo
865 DmaMode
|= V_8237_DMA_CHMODE_SINGLE
;
868 // A Slave DMA transfer can not cross a 64K boundary.
869 // Compute *NumberOfBytes based on this restriction.
871 MaxNumberOfBytes
= 0x10000 - ((UINT32
) (*DeviceAddress
) & 0xffff);
872 if (*NumberOfBytes
> MaxNumberOfBytes
) {
873 *NumberOfBytes
= MaxNumberOfBytes
;
876 // Compute the values to program into the BaseAddress and Count registers
877 // of the Slave DMA controller
879 BaseAddress
= (UINT32
) (*DeviceAddress
);
880 Count
= (UINT16
) (*NumberOfBytes
- 1);
882 // Program the DMA Write Single Mask Register for ChannelNumber
883 // Clear the DMA Byte Pointer Register
885 DmaMask
= R_8237_DMA_WRSMSK_CH0_3
;
886 DmaClear
= R_8237_DMA_CBPR_CH0_3
;
887 DmaChannelMode
= R_8237_DMA_CHMODE_CH0_3
;
892 (UINT8
) (B_8237_DMA_WRSMSK_CMS
| (ChannelNumber
& 0x03))
894 if (EFI_ERROR (Status
)) {
901 (UINT8
) (B_8237_DMA_WRSMSK_CMS
| (ChannelNumber
& 0x03))
903 if (EFI_ERROR (Status
)) {
907 Status
= WritePort (This
, DmaChannelMode
, DmaMode
);
908 if (EFI_ERROR (Status
)) {
912 Status
= WriteDmaPort (
914 mDmaRegisters
[ChannelNumber
].Address
,
915 mDmaRegisters
[ChannelNumber
].Page
,
916 mDmaRegisters
[ChannelNumber
].Count
,
920 if (EFI_ERROR (Status
)) {
927 (UINT8
) (ChannelNumber
& 0x03)
929 if (EFI_ERROR (Status
)) {
937 Maps a memory region for DMA. This implementation implement the
938 the full mapping support.
940 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
941 @param Operation Indicates the type of DMA (slave or bus master), and if
942 the DMA operation is going to read or write to system memory.
943 @param ChannelNumber The slave channel number to use for this DMA operation.
944 If Operation and ChannelAttributes shows that this device
945 performs bus mastering DMA, then this field is ignored.
946 The legal range for this field is 0..7.
947 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
948 @param HostAddress The system memory address to map to the device.
949 @param NumberOfBytes On input the number of bytes to map. On output the number
950 of bytes that were mapped.
951 @param DeviceAddress The resulting map address for the bus master device to use
952 to access the hosts HostAddress.
953 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
955 @retval EFI_SUCCESS - The range was mapped for the returned NumberOfBytes.
956 @retval EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined.
957 @retval EFI_UNSUPPORTED - The HostAddress can not be mapped as a common buffer.
958 @retval EFI_DEVICE_ERROR - The system hardware could not map the requested address.
959 @retval EFI_OUT_OF_RESOURCES - The memory pages could not be allocated.
962 IsaIoMapFullSupport (
963 IN EFI_ISA_IO_PROTOCOL
*This
,
964 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation
,
965 IN UINT8 ChannelNumber OPTIONAL
,
966 IN UINT32 ChannelAttributes
,
967 IN VOID
*HostAddress
,
968 IN OUT UINTN
*NumberOfBytes
,
969 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
976 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
977 ISA_MAP_INFO
*IsaMapInfo
;
979 UINTN MaxNumberOfBytes
;
984 UINT8 DmaChannelMode
;
986 if ((NULL
== This
) ||
987 (NULL
== HostAddress
) ||
988 (NULL
== NumberOfBytes
) ||
989 (NULL
== DeviceAddress
) ||
992 return EFI_INVALID_PARAMETER
;
996 // Initialize the return values to their defaults
1001 // Make sure the Operation parameter is valid
1003 if (Operation
< 0 || Operation
>= EfiIsaIoOperationMaximum
) {
1004 return EFI_INVALID_PARAMETER
;
1007 if (ChannelNumber
>= 8) {
1008 return EFI_INVALID_PARAMETER
;
1012 // See if this is a Slave DMA Operation
1016 if (Operation
== EfiIsaIoOperationSlaveRead
) {
1017 Operation
= EfiIsaIoOperationBusMasterRead
;
1022 if (Operation
== EfiIsaIoOperationSlaveWrite
) {
1023 Operation
= EfiIsaIoOperationBusMasterWrite
;
1030 // Make sure that ChannelNumber is a valid channel number
1031 // Channel 4 is used to cascade, so it is illegal.
1033 if (ChannelNumber
== 4 || ChannelNumber
> 7) {
1034 return EFI_INVALID_PARAMETER
;
1037 // This implementation only support COMPATIBLE DMA Transfers
1039 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE
) == 0) {
1040 return EFI_INVALID_PARAMETER
;
1043 if ((ChannelAttributes
&
1044 (EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A
|
1045 EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B
|
1046 EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C
)) != 0) {
1047 return EFI_INVALID_PARAMETER
;
1050 if (ChannelNumber
< 4) {
1052 // If this is Channel 0..3, then the width must be 8 bit
1054 if (((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8
) == 0) ||
1055 ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16
) != 0)
1057 return EFI_INVALID_PARAMETER
;
1061 // If this is Channel 4..7, then the width must be 16 bit
1063 if (((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8
) != 0) ||
1064 ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16
) == 0)) {
1065 return EFI_INVALID_PARAMETER
;
1069 // Either Demand Mode or Single Mode must be selected, but not both
1071 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE
) != 0) {
1072 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE
) != 0) {
1073 return EFI_INVALID_PARAMETER
;
1076 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE
) == 0) {
1077 return EFI_INVALID_PARAMETER
;
1082 // Map the HostAddress to a DeviceAddress.
1084 PhysicalAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
;
1085 if ((PhysicalAddress
+*NumberOfBytes
) > ISA_MAX_MEMORY_ADDRESS
) {
1087 // Common Buffer operations can not be remapped. If the common buffer
1088 // is above 16MB, then it is not possible to generate a mapping, so return
1091 if (Operation
== EfiIsaIoOperationBusMasterCommonBuffer
) {
1092 return EFI_UNSUPPORTED
;
1095 // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
1098 IsaMapInfo
= AllocatePool (sizeof (ISA_MAP_INFO
));
1099 if (IsaMapInfo
== NULL
) {
1101 return EFI_OUT_OF_RESOURCES
;
1104 // Return a pointer to the MAP_INFO structure in Mapping
1106 *Mapping
= IsaMapInfo
;
1109 // Initialize the MAP_INFO structure
1111 IsaMapInfo
->Operation
= Operation
;
1112 IsaMapInfo
->NumberOfBytes
= *NumberOfBytes
;
1113 IsaMapInfo
->NumberOfPages
= EFI_SIZE_TO_PAGES (*NumberOfBytes
);
1114 IsaMapInfo
->HostAddress
= PhysicalAddress
;
1115 IsaMapInfo
->MappedHostAddress
= ISA_MAX_MEMORY_ADDRESS
- 1;
1118 // Allocate a buffer below 16MB to map the transfer to.
1120 Status
= gBS
->AllocatePages (
1122 EfiBootServicesData
,
1123 IsaMapInfo
->NumberOfPages
,
1124 &IsaMapInfo
->MappedHostAddress
1126 if (EFI_ERROR (Status
)) {
1127 FreePool (IsaMapInfo
);
1133 // If this is a read operation from the DMA agents's point of view,
1134 // then copy the contents of the real buffer into the mapped buffer
1135 // so the DMA agent can read the contents of the real buffer.
1137 if (Operation
== EfiIsaIoOperationBusMasterRead
) {
1139 (VOID
*) (UINTN
) IsaMapInfo
->MappedHostAddress
,
1140 (VOID
*) (UINTN
) IsaMapInfo
->HostAddress
,
1141 IsaMapInfo
->NumberOfBytes
1145 // The DeviceAddress is the address of the maped buffer below 16 MB
1147 *DeviceAddress
= IsaMapInfo
->MappedHostAddress
;
1150 // The transfer is below 16 MB, so the DeviceAddress is simply the
1153 *DeviceAddress
= PhysicalAddress
;
1156 // If this is a Bus Master operation then return
1162 // Figure out what to program into the DMA Channel Mode Register
1164 DmaMode
= (UINT8
) (B_8237_DMA_CHMODE_INCREMENT
| (ChannelNumber
& 0x03));
1166 DmaMode
|= V_8237_DMA_CHMODE_MEM2IO
;
1168 DmaMode
|= V_8237_DMA_CHMODE_IO2MEM
;
1171 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_AUTO_INITIALIZE
) != 0) {
1172 DmaMode
|= B_8237_DMA_CHMODE_AE
;
1175 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE
) != 0) {
1176 DmaMode
|= V_8237_DMA_CHMODE_DEMAND
;
1179 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE
) != 0) {
1180 DmaMode
|= V_8237_DMA_CHMODE_SINGLE
;
1183 // A Slave DMA transfer can not cross a 64K boundary.
1184 // Compute *NumberOfBytes based on this restriction.
1186 MaxNumberOfBytes
= 0x10000 - ((UINT32
) (*DeviceAddress
) & 0xffff);
1187 if (*NumberOfBytes
> MaxNumberOfBytes
) {
1188 *NumberOfBytes
= MaxNumberOfBytes
;
1191 // Compute the values to program into the BaseAddress and Count registers
1192 // of the Slave DMA controller
1194 if (ChannelNumber
< 4) {
1195 BaseAddress
= (UINT32
) (*DeviceAddress
);
1196 Count
= (UINT16
) (*NumberOfBytes
- 1);
1198 BaseAddress
= (UINT32
) (((UINT32
) (*DeviceAddress
) & 0xff0000) | (((UINT32
) (*DeviceAddress
) & 0xffff) >> 1));
1199 Count
= (UINT16
) ((*NumberOfBytes
- 1) >> 1);
1202 // Program the DMA Write Single Mask Register for ChannelNumber
1203 // Clear the DMA Byte Pointer Register
1205 if (ChannelNumber
< 4) {
1206 DmaMask
= R_8237_DMA_WRSMSK_CH0_3
;
1207 DmaClear
= R_8237_DMA_CBPR_CH0_3
;
1208 DmaChannelMode
= R_8237_DMA_CHMODE_CH0_3
;
1210 DmaMask
= R_8237_DMA_WRSMSK_CH4_7
;
1211 DmaClear
= R_8237_DMA_CBPR_CH4_7
;
1212 DmaChannelMode
= R_8237_DMA_CHMODE_CH4_7
;
1215 Status
= WritePort (
1218 (UINT8
) (B_8237_DMA_WRSMSK_CMS
| (ChannelNumber
& 0x03))
1220 if (EFI_ERROR (Status
)) {
1224 Status
= WritePort (
1227 (UINT8
) (B_8237_DMA_WRSMSK_CMS
| (ChannelNumber
& 0x03))
1229 if (EFI_ERROR (Status
)) {
1233 Status
= WritePort (This
, DmaChannelMode
, DmaMode
);
1234 if (EFI_ERROR (Status
)) {
1238 Status
= WriteDmaPort (
1240 mDmaRegisters
[ChannelNumber
].Address
,
1241 mDmaRegisters
[ChannelNumber
].Page
,
1242 mDmaRegisters
[ChannelNumber
].Count
,
1246 if (EFI_ERROR (Status
)) {
1250 Status
= WritePort (
1253 (UINT8
) (ChannelNumber
& 0x03)
1255 if (EFI_ERROR (Status
)) {
1263 Maps a memory region for DMA
1265 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1266 @param Operation Indicates the type of DMA (slave or bus master), and if
1267 the DMA operation is going to read or write to system memory.
1268 @param ChannelNumber The slave channel number to use for this DMA operation.
1269 If Operation and ChannelAttributes shows that this device
1270 performs bus mastering DMA, then this field is ignored.
1271 The legal range for this field is 0..7.
1272 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
1273 @param HostAddress The system memory address to map to the device.
1274 @param NumberOfBytes On input the number of bytes to map. On output the number
1275 of bytes that were mapped.
1276 @param DeviceAddress The resulting map address for the bus master device to use
1277 to access the hosts HostAddress.
1278 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
1280 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
1281 @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.
1282 @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.
1283 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
1284 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
1289 IN EFI_ISA_IO_PROTOCOL
*This
,
1290 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation
,
1291 IN UINT8 ChannelNumber OPTIONAL
,
1292 IN UINT32 ChannelAttributes
,
1293 IN VOID
*HostAddress
,
1294 IN OUT UINTN
*NumberOfBytes
,
1295 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
1300 // Check if DMA is supported.
1302 if ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_SUPPORT_DMA
) == 0) {
1303 return EFI_UNSUPPORTED
;
1306 // Set Feature Flag PcdIsaBusSupportBusMaster to FALSE to disable support for
1309 // So we just return EFI_UNSUPPORTED for these functions.
1311 if ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA
) != 0) {
1312 return IsaIoMapOnlySupportSlaveReadWrite (
1324 return IsaIoMapFullSupport (
1338 Allocates pages that are suitable for an EfiIsaIoOperationBusMasterCommonBuffer mapping.
1340 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1341 @param[in] Type The type allocation to perform.
1342 @param[in] MemoryType The type of memory to allocate.
1343 @param[in] Pages The number of pages to allocate.
1344 @param[out] HostAddress A pointer to store the base address of the allocated range.
1345 @param[in] Attributes The requested bit mask of attributes for the allocated range.
1347 @retval EFI_SUCCESS The requested memory pages were allocated.
1348 @retval EFI_INVALID_PARAMETER Type is invalid or MemoryType is invalid or HostAddress is NULL
1349 @retval EFI_UNSUPPORTED Attributes is unsupported or the memory range specified
1350 by HostAddress, Pages, and Type is not available for common buffer use.
1351 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
1355 IsaIoAllocateBuffer (
1356 IN EFI_ISA_IO_PROTOCOL
*This
,
1357 IN EFI_ALLOCATE_TYPE Type
,
1358 IN EFI_MEMORY_TYPE MemoryType
,
1360 OUT VOID
**HostAddress
,
1361 IN UINT64 Attributes
1365 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
1368 // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
1370 // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
1372 if (((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_SUPPORT_DMA
) == 0) ||
1373 ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA
) != 0)) {
1374 return EFI_UNSUPPORTED
;
1377 if (HostAddress
== NULL
) {
1378 return EFI_INVALID_PARAMETER
;
1381 if (Type
< AllocateAnyPages
|| Type
>= MaxAllocateType
) {
1382 return EFI_INVALID_PARAMETER
;
1385 // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
1387 if (MemoryType
!= EfiBootServicesData
&& MemoryType
!= EfiRuntimeServicesData
) {
1388 return EFI_INVALID_PARAMETER
;
1391 if ((Attributes
& ~(EFI_ISA_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE
| EFI_ISA_IO_ATTRIBUTE_MEMORY_CACHED
)) != 0) {
1392 return EFI_UNSUPPORTED
;
1395 PhysicalAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) (ISA_MAX_MEMORY_ADDRESS
- 1);
1396 if (Type
== AllocateAddress
) {
1397 if ((UINTN
) (*HostAddress
) >= ISA_MAX_MEMORY_ADDRESS
) {
1398 return EFI_UNSUPPORTED
;
1400 PhysicalAddress
= (UINTN
) (*HostAddress
);
1404 if (Type
== AllocateAnyPages
) {
1405 Type
= AllocateMaxAddress
;
1408 Status
= gBS
->AllocatePages (Type
, MemoryType
, Pages
, &PhysicalAddress
);
1409 if (EFI_ERROR (Status
)) {
1410 REPORT_STATUS_CODE (
1411 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1412 EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
1417 *HostAddress
= (VOID
*) (UINTN
) PhysicalAddress
;
1422 Frees memory that was allocated with EFI_ISA_IO.AllocateBuffer().
1424 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1425 @param[in] Pages The number of pages to free.
1426 @param[in] HostAddress The base address of the allocated range.
1428 @retval EFI_SUCCESS The requested memory pages were freed.
1429 @retval EFI_INVALID_PARAMETER The memory was not allocated with EFI_ISA_IO.AllocateBufer().
1434 IN EFI_ISA_IO_PROTOCOL
*This
,
1436 IN VOID
*HostAddress
1442 // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
1444 // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
1446 if (((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_SUPPORT_DMA
) == 0) ||
1447 ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA
) != 0)) {
1448 return EFI_UNSUPPORTED
;
1451 Status
= gBS
->FreePages (
1452 (EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
,
1455 if (EFI_ERROR (Status
)) {
1456 REPORT_STATUS_CODE (
1457 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1458 EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR