2 The implementation for EFI_ISA_IO_PROTOCOL.
4 Copyright (c) 2006 - 2012, 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 ((UINT32
)Width
>= EfiIsaIoWidthMaximum
||
443 Width
== EfiIsaIoWidthReserved
||
444 Width
== EfiIsaIoWidthFifoReserved
||
445 Width
== EfiIsaIoWidthFillReserved
447 return EFI_INVALID_PARAMETER
;
451 // If Width is EfiIsaIoWidthFifoUintX then convert to EfiIsaIoWidthUintX
452 // If Width is EfiIsaIoWidthFillUintX then convert to EfiIsaIoWidthUintX
454 if (Width
>= EfiIsaIoWidthFifoUint8
&& Width
< EfiIsaIoWidthFifoReserved
) {
458 Width
= (EFI_ISA_IO_PROTOCOL_WIDTH
) (Width
& 0x03);
460 Status
= EFI_UNSUPPORTED
;
461 Item
= IsaIoDevice
->IsaIo
.ResourceList
->ResourceItem
;
462 while (Item
->Type
!= EfiIsaAcpiResourceEndOfList
) {
463 if ((Type
== IsaAccessTypeMem
&& Item
->Type
== EfiIsaAcpiResourceMemory
) ||
464 (Type
== IsaAccessTypeIo
&& Item
->Type
== EfiIsaAcpiResourceIo
)) {
465 if (Offset
>= Item
->StartRange
&& (Offset
+ Count
* (UINT32
)(1 << Width
)) - 1 <= Item
->EndRange
) {
469 if (Offset
>= Item
->StartRange
&& Offset
<= Item
->EndRange
) {
470 Status
= EFI_INVALID_PARAMETER
;
481 Performs an ISA Memory Read Cycle
483 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
484 @param[in] Width Specifies the width of the memory operation.
485 @param[in] Offset The offset in ISA memory space to start the memory operation.
486 @param[in] Count The number of memory operations to perform.
487 @param[out] Buffer The destination buffer to store the results
489 @retval EFI_SUCCESS The data was read from the device successfully.
490 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
491 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
492 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
497 IN EFI_ISA_IO_PROTOCOL
*This
,
498 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
505 ISA_IO_DEVICE
*IsaIoDevice
;
508 // Check if ISA memory is supported.
510 if ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY
) == 0) {
511 return EFI_UNSUPPORTED
;
514 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
517 // Verify the Isa Io Access
519 Status
= IsaIoVerifyAccess (
526 if (EFI_ERROR (Status
)) {
530 Status
= IsaIoDevice
->PciIo
->Mem
.Read (
532 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
533 EFI_PCI_IO_PASS_THROUGH_BAR
,
539 if (EFI_ERROR (Status
)) {
541 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
542 EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
550 Performs an ISA Memory Write Cycle
552 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
553 @param[in] Width Specifies the width of the memory operation.
554 @param[in] Offset The offset in ISA memory space to start the memory operation.
555 @param[in] Count The number of memory operations to perform.
556 @param[in] Buffer The source buffer to write data from
558 @retval EFI_SUCCESS The data was written to the device sucessfully.
559 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
560 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
561 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
566 IN EFI_ISA_IO_PROTOCOL
*This
,
567 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
574 ISA_IO_DEVICE
*IsaIoDevice
;
577 // Check if ISA memory is supported.
579 if ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY
) == 0) {
580 return EFI_UNSUPPORTED
;
583 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
586 // Verify Isa IO Access
588 Status
= IsaIoVerifyAccess (
595 if (EFI_ERROR (Status
)) {
599 Status
= IsaIoDevice
->PciIo
->Mem
.Write (
601 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
602 EFI_PCI_IO_PASS_THROUGH_BAR
,
608 if (EFI_ERROR (Status
)) {
610 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
611 EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
619 Copy one region of ISA memory space to another region of ISA memory space on the ISA controller.
621 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
622 @param[in] Width Specifies the width of the memory copy operation.
623 @param[in] DestOffset The offset of the destination
624 @param[in] SrcOffset The offset of the source
625 @param[in] Count The number of memory copy operations to perform
627 @retval EFI_SUCCESS The data was copied sucessfully.
628 @retval EFI_UNSUPPORTED The DestOffset or SrcOffset is not valid for this device.
629 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
630 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
635 IN EFI_ISA_IO_PROTOCOL
*This
,
636 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
637 IN UINT32 DestOffset
,
643 ISA_IO_DEVICE
*IsaIoDevice
;
646 // Check if ISA memory is supported.
648 if ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY
) == 0) {
649 return EFI_UNSUPPORTED
;
652 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
655 // Verify Isa IO Access for destination and source
657 Status
= IsaIoVerifyAccess (
664 if (EFI_ERROR (Status
)) {
668 Status
= IsaIoVerifyAccess (
675 if (EFI_ERROR (Status
)) {
679 Status
= IsaIoDevice
->PciIo
->CopyMem (
681 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
682 EFI_PCI_IO_PASS_THROUGH_BAR
,
684 EFI_PCI_IO_PASS_THROUGH_BAR
,
689 if (EFI_ERROR (Status
)) {
691 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
692 EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
700 Maps a memory region for DMA, note this implementation
701 only supports slave read/write operation to save code size.
703 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
704 @param Operation Indicates the type of DMA (slave or bus master), and if
705 the DMA operation is going to read or write to system memory.
706 @param ChannelNumber The slave channel number to use for this DMA operation.
707 If Operation and ChannelAttributes shows that this device
708 performs bus mastering DMA, then this field is ignored.
709 The legal range for this field is 0..7.
710 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
711 @param HostAddress The system memory address to map to the device.
712 @param NumberOfBytes On input the number of bytes to map. On output the number
713 of bytes that were mapped.
714 @param DeviceAddress The resulting map address for the bus master device to use
715 to access the hosts HostAddress.
716 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
718 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
719 @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.
720 @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.
721 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
722 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
725 IsaIoMapOnlySupportSlaveReadWrite (
726 IN EFI_ISA_IO_PROTOCOL
*This
,
727 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation
,
728 IN UINT8 ChannelNumber OPTIONAL
,
729 IN UINT32 ChannelAttributes
,
730 IN VOID
*HostAddress
,
731 IN OUT UINTN
*NumberOfBytes
,
732 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
737 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
738 ISA_MAP_INFO
*IsaMapInfo
;
740 UINTN MaxNumberOfBytes
;
745 UINT8 DmaChannelMode
;
747 if ((NULL
== This
) ||
748 (NULL
== HostAddress
) ||
749 (NULL
== NumberOfBytes
) ||
750 (NULL
== DeviceAddress
) ||
753 return EFI_INVALID_PARAMETER
;
757 // Initialize the return values to their defaults
762 // Make sure the Operation parameter is valid.
763 // Light IsaIo only supports two operations.
765 if (!(Operation
== EfiIsaIoOperationSlaveRead
||
766 Operation
== EfiIsaIoOperationSlaveWrite
)) {
767 return EFI_INVALID_PARAMETER
;
770 if (ChannelNumber
>= 4) {
772 // The Light IsaIo doesn't support channelNumber larger than 4.
774 return EFI_INVALID_PARAMETER
;
778 // Map the HostAddress to a DeviceAddress.
780 PhysicalAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
;
781 if ((PhysicalAddress
+ *NumberOfBytes
) > ISA_MAX_MEMORY_ADDRESS
) {
783 // Common Buffer operations can not be remapped. If the common buffer
784 // is above 16MB, then it is not possible to generate a mapping, so return
787 if (Operation
== EfiIsaIoOperationBusMasterCommonBuffer
) {
788 return EFI_UNSUPPORTED
;
791 // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
794 IsaMapInfo
= AllocatePool (sizeof (ISA_MAP_INFO
));
795 if (IsaMapInfo
== NULL
) {
797 return EFI_OUT_OF_RESOURCES
;
800 // Return a pointer to the MAP_INFO structure in Mapping
802 *Mapping
= IsaMapInfo
;
805 // Initialize the MAP_INFO structure
807 IsaMapInfo
->Operation
= Operation
;
808 IsaMapInfo
->NumberOfBytes
= *NumberOfBytes
;
809 IsaMapInfo
->NumberOfPages
= EFI_SIZE_TO_PAGES (*NumberOfBytes
);
810 IsaMapInfo
->HostAddress
= PhysicalAddress
;
811 IsaMapInfo
->MappedHostAddress
= ISA_MAX_MEMORY_ADDRESS
- 1;
814 // Allocate a buffer below 16MB to map the transfer to.
816 Status
= gBS
->AllocatePages (
819 IsaMapInfo
->NumberOfPages
,
820 &IsaMapInfo
->MappedHostAddress
822 if (EFI_ERROR (Status
)) {
823 FreePool (IsaMapInfo
);
829 // If this is a read operation from the DMA agents's point of view,
830 // then copy the contents of the real buffer into the mapped buffer
831 // so the DMA agent can read the contents of the real buffer.
833 if (Operation
== EfiIsaIoOperationSlaveRead
) {
835 (VOID
*) (UINTN
) IsaMapInfo
->MappedHostAddress
,
836 (VOID
*) (UINTN
) IsaMapInfo
->HostAddress
,
837 IsaMapInfo
->NumberOfBytes
841 // The DeviceAddress is the address of the maped buffer below 16 MB
843 *DeviceAddress
= IsaMapInfo
->MappedHostAddress
;
846 // The transfer is below 16 MB, so the DeviceAddress is simply the
849 *DeviceAddress
= PhysicalAddress
;
853 // Figure out what to program into the DMA Channel Mode Register
855 DmaMode
= (UINT8
) (B_8237_DMA_CHMODE_INCREMENT
| (ChannelNumber
& 0x03));
856 if (Operation
== EfiIsaIoOperationSlaveRead
) {
857 DmaMode
|= V_8237_DMA_CHMODE_MEM2IO
;
859 DmaMode
|= V_8237_DMA_CHMODE_IO2MEM
;
862 // We only support EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE in simplified IsaIo
864 DmaMode
|= V_8237_DMA_CHMODE_SINGLE
;
867 // A Slave DMA transfer can not cross a 64K boundary.
868 // Compute *NumberOfBytes based on this restriction.
870 MaxNumberOfBytes
= 0x10000 - ((UINT32
) (*DeviceAddress
) & 0xffff);
871 if (*NumberOfBytes
> MaxNumberOfBytes
) {
872 *NumberOfBytes
= MaxNumberOfBytes
;
875 // Compute the values to program into the BaseAddress and Count registers
876 // of the Slave DMA controller
878 BaseAddress
= (UINT32
) (*DeviceAddress
);
879 Count
= (UINT16
) (*NumberOfBytes
- 1);
881 // Program the DMA Write Single Mask Register for ChannelNumber
882 // Clear the DMA Byte Pointer Register
884 DmaMask
= R_8237_DMA_WRSMSK_CH0_3
;
885 DmaClear
= R_8237_DMA_CBPR_CH0_3
;
886 DmaChannelMode
= R_8237_DMA_CHMODE_CH0_3
;
891 (UINT8
) (B_8237_DMA_WRSMSK_CMS
| (ChannelNumber
& 0x03))
893 if (EFI_ERROR (Status
)) {
900 (UINT8
) (B_8237_DMA_WRSMSK_CMS
| (ChannelNumber
& 0x03))
902 if (EFI_ERROR (Status
)) {
906 Status
= WritePort (This
, DmaChannelMode
, DmaMode
);
907 if (EFI_ERROR (Status
)) {
911 Status
= WriteDmaPort (
913 mDmaRegisters
[ChannelNumber
].Address
,
914 mDmaRegisters
[ChannelNumber
].Page
,
915 mDmaRegisters
[ChannelNumber
].Count
,
919 if (EFI_ERROR (Status
)) {
926 (UINT8
) (ChannelNumber
& 0x03)
928 if (EFI_ERROR (Status
)) {
936 Maps a memory region for DMA. This implementation implement the
937 the full mapping support.
939 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
940 @param Operation Indicates the type of DMA (slave or bus master), and if
941 the DMA operation is going to read or write to system memory.
942 @param ChannelNumber The slave channel number to use for this DMA operation.
943 If Operation and ChannelAttributes shows that this device
944 performs bus mastering DMA, then this field is ignored.
945 The legal range for this field is 0..7.
946 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
947 @param HostAddress The system memory address to map to the device.
948 @param NumberOfBytes On input the number of bytes to map. On output the number
949 of bytes that were mapped.
950 @param DeviceAddress The resulting map address for the bus master device to use
951 to access the hosts HostAddress.
952 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
954 @retval EFI_SUCCESS - The range was mapped for the returned NumberOfBytes.
955 @retval EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined.
956 @retval EFI_UNSUPPORTED - The HostAddress can not be mapped as a common buffer.
957 @retval EFI_DEVICE_ERROR - The system hardware could not map the requested address.
958 @retval EFI_OUT_OF_RESOURCES - The memory pages could not be allocated.
961 IsaIoMapFullSupport (
962 IN EFI_ISA_IO_PROTOCOL
*This
,
963 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation
,
964 IN UINT8 ChannelNumber OPTIONAL
,
965 IN UINT32 ChannelAttributes
,
966 IN VOID
*HostAddress
,
967 IN OUT UINTN
*NumberOfBytes
,
968 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
975 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
976 ISA_MAP_INFO
*IsaMapInfo
;
978 UINTN MaxNumberOfBytes
;
983 UINT8 DmaChannelMode
;
985 if ((NULL
== This
) ||
986 (NULL
== HostAddress
) ||
987 (NULL
== NumberOfBytes
) ||
988 (NULL
== DeviceAddress
) ||
991 return EFI_INVALID_PARAMETER
;
995 // Initialize the return values to their defaults
1000 // Make sure the Operation parameter is valid
1002 if ((UINT32
)Operation
>= EfiIsaIoOperationMaximum
) {
1003 return EFI_INVALID_PARAMETER
;
1006 if (ChannelNumber
>= 8) {
1007 return EFI_INVALID_PARAMETER
;
1011 // See if this is a Slave DMA Operation
1015 if (Operation
== EfiIsaIoOperationSlaveRead
) {
1016 Operation
= EfiIsaIoOperationBusMasterRead
;
1021 if (Operation
== EfiIsaIoOperationSlaveWrite
) {
1022 Operation
= EfiIsaIoOperationBusMasterWrite
;
1029 // Make sure that ChannelNumber is a valid channel number
1030 // Channel 4 is used to cascade, so it is illegal.
1032 if (ChannelNumber
== 4 || ChannelNumber
> 7) {
1033 return EFI_INVALID_PARAMETER
;
1036 // This implementation only support COMPATIBLE DMA Transfers
1038 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE
) == 0) {
1039 return EFI_INVALID_PARAMETER
;
1042 if ((ChannelAttributes
&
1043 (EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A
|
1044 EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B
|
1045 EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C
)) != 0) {
1046 return EFI_INVALID_PARAMETER
;
1049 if (ChannelNumber
< 4) {
1051 // If this is Channel 0..3, then the width must be 8 bit
1053 if (((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8
) == 0) ||
1054 ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16
) != 0)
1056 return EFI_INVALID_PARAMETER
;
1060 // If this is Channel 4..7, then the width must be 16 bit
1062 if (((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8
) != 0) ||
1063 ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16
) == 0)) {
1064 return EFI_INVALID_PARAMETER
;
1068 // Either Demand Mode or Single Mode must be selected, but not both
1070 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE
) != 0) {
1071 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE
) != 0) {
1072 return EFI_INVALID_PARAMETER
;
1075 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE
) == 0) {
1076 return EFI_INVALID_PARAMETER
;
1081 // Map the HostAddress to a DeviceAddress.
1083 PhysicalAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
;
1084 if ((PhysicalAddress
+*NumberOfBytes
) > ISA_MAX_MEMORY_ADDRESS
) {
1086 // Common Buffer operations can not be remapped. If the common buffer
1087 // is above 16MB, then it is not possible to generate a mapping, so return
1090 if (Operation
== EfiIsaIoOperationBusMasterCommonBuffer
) {
1091 return EFI_UNSUPPORTED
;
1094 // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
1097 IsaMapInfo
= AllocatePool (sizeof (ISA_MAP_INFO
));
1098 if (IsaMapInfo
== NULL
) {
1100 return EFI_OUT_OF_RESOURCES
;
1103 // Return a pointer to the MAP_INFO structure in Mapping
1105 *Mapping
= IsaMapInfo
;
1108 // Initialize the MAP_INFO structure
1110 IsaMapInfo
->Operation
= Operation
;
1111 IsaMapInfo
->NumberOfBytes
= *NumberOfBytes
;
1112 IsaMapInfo
->NumberOfPages
= EFI_SIZE_TO_PAGES (*NumberOfBytes
);
1113 IsaMapInfo
->HostAddress
= PhysicalAddress
;
1114 IsaMapInfo
->MappedHostAddress
= ISA_MAX_MEMORY_ADDRESS
- 1;
1117 // Allocate a buffer below 16MB to map the transfer to.
1119 Status
= gBS
->AllocatePages (
1121 EfiBootServicesData
,
1122 IsaMapInfo
->NumberOfPages
,
1123 &IsaMapInfo
->MappedHostAddress
1125 if (EFI_ERROR (Status
)) {
1126 FreePool (IsaMapInfo
);
1132 // If this is a read operation from the DMA agents's point of view,
1133 // then copy the contents of the real buffer into the mapped buffer
1134 // so the DMA agent can read the contents of the real buffer.
1136 if (Operation
== EfiIsaIoOperationBusMasterRead
) {
1138 (VOID
*) (UINTN
) IsaMapInfo
->MappedHostAddress
,
1139 (VOID
*) (UINTN
) IsaMapInfo
->HostAddress
,
1140 IsaMapInfo
->NumberOfBytes
1144 // The DeviceAddress is the address of the maped buffer below 16 MB
1146 *DeviceAddress
= IsaMapInfo
->MappedHostAddress
;
1149 // The transfer is below 16 MB, so the DeviceAddress is simply the
1152 *DeviceAddress
= PhysicalAddress
;
1155 // If this is a Bus Master operation then return
1161 // Figure out what to program into the DMA Channel Mode Register
1163 DmaMode
= (UINT8
) (B_8237_DMA_CHMODE_INCREMENT
| (ChannelNumber
& 0x03));
1165 DmaMode
|= V_8237_DMA_CHMODE_MEM2IO
;
1167 DmaMode
|= V_8237_DMA_CHMODE_IO2MEM
;
1170 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_AUTO_INITIALIZE
) != 0) {
1171 DmaMode
|= B_8237_DMA_CHMODE_AE
;
1174 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE
) != 0) {
1175 DmaMode
|= V_8237_DMA_CHMODE_DEMAND
;
1178 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE
) != 0) {
1179 DmaMode
|= V_8237_DMA_CHMODE_SINGLE
;
1182 // A Slave DMA transfer can not cross a 64K boundary.
1183 // Compute *NumberOfBytes based on this restriction.
1185 MaxNumberOfBytes
= 0x10000 - ((UINT32
) (*DeviceAddress
) & 0xffff);
1186 if (*NumberOfBytes
> MaxNumberOfBytes
) {
1187 *NumberOfBytes
= MaxNumberOfBytes
;
1190 // Compute the values to program into the BaseAddress and Count registers
1191 // of the Slave DMA controller
1193 if (ChannelNumber
< 4) {
1194 BaseAddress
= (UINT32
) (*DeviceAddress
);
1195 Count
= (UINT16
) (*NumberOfBytes
- 1);
1197 BaseAddress
= (UINT32
) (((UINT32
) (*DeviceAddress
) & 0xff0000) | (((UINT32
) (*DeviceAddress
) & 0xffff) >> 1));
1198 Count
= (UINT16
) ((*NumberOfBytes
- 1) >> 1);
1201 // Program the DMA Write Single Mask Register for ChannelNumber
1202 // Clear the DMA Byte Pointer Register
1204 if (ChannelNumber
< 4) {
1205 DmaMask
= R_8237_DMA_WRSMSK_CH0_3
;
1206 DmaClear
= R_8237_DMA_CBPR_CH0_3
;
1207 DmaChannelMode
= R_8237_DMA_CHMODE_CH0_3
;
1209 DmaMask
= R_8237_DMA_WRSMSK_CH4_7
;
1210 DmaClear
= R_8237_DMA_CBPR_CH4_7
;
1211 DmaChannelMode
= R_8237_DMA_CHMODE_CH4_7
;
1214 Status
= WritePort (
1217 (UINT8
) (B_8237_DMA_WRSMSK_CMS
| (ChannelNumber
& 0x03))
1219 if (EFI_ERROR (Status
)) {
1223 Status
= WritePort (
1226 (UINT8
) (B_8237_DMA_WRSMSK_CMS
| (ChannelNumber
& 0x03))
1228 if (EFI_ERROR (Status
)) {
1232 Status
= WritePort (This
, DmaChannelMode
, DmaMode
);
1233 if (EFI_ERROR (Status
)) {
1237 Status
= WriteDmaPort (
1239 mDmaRegisters
[ChannelNumber
].Address
,
1240 mDmaRegisters
[ChannelNumber
].Page
,
1241 mDmaRegisters
[ChannelNumber
].Count
,
1245 if (EFI_ERROR (Status
)) {
1249 Status
= WritePort (
1252 (UINT8
) (ChannelNumber
& 0x03)
1254 if (EFI_ERROR (Status
)) {
1262 Maps a memory region for DMA
1264 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1265 @param Operation Indicates the type of DMA (slave or bus master), and if
1266 the DMA operation is going to read or write to system memory.
1267 @param ChannelNumber The slave channel number to use for this DMA operation.
1268 If Operation and ChannelAttributes shows that this device
1269 performs bus mastering DMA, then this field is ignored.
1270 The legal range for this field is 0..7.
1271 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
1272 @param HostAddress The system memory address to map to the device.
1273 @param NumberOfBytes On input the number of bytes to map. On output the number
1274 of bytes that were mapped.
1275 @param DeviceAddress The resulting map address for the bus master device to use
1276 to access the hosts HostAddress.
1277 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
1279 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
1280 @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.
1281 @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.
1282 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
1283 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
1288 IN EFI_ISA_IO_PROTOCOL
*This
,
1289 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation
,
1290 IN UINT8 ChannelNumber OPTIONAL
,
1291 IN UINT32 ChannelAttributes
,
1292 IN VOID
*HostAddress
,
1293 IN OUT UINTN
*NumberOfBytes
,
1294 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
1299 // Check if DMA is supported.
1301 if ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_SUPPORT_DMA
) == 0) {
1302 return EFI_UNSUPPORTED
;
1305 // Set Feature Flag PcdIsaBusSupportBusMaster to FALSE to disable support for
1308 // So we just return EFI_UNSUPPORTED for these functions.
1310 if ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA
) != 0) {
1311 return IsaIoMapOnlySupportSlaveReadWrite (
1323 return IsaIoMapFullSupport (
1337 Allocates pages that are suitable for an EfiIsaIoOperationBusMasterCommonBuffer mapping.
1339 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1340 @param[in] Type The type allocation to perform.
1341 @param[in] MemoryType The type of memory to allocate.
1342 @param[in] Pages The number of pages to allocate.
1343 @param[out] HostAddress A pointer to store the base address of the allocated range.
1344 @param[in] Attributes The requested bit mask of attributes for the allocated range.
1346 @retval EFI_SUCCESS The requested memory pages were allocated.
1347 @retval EFI_INVALID_PARAMETER Type is invalid or MemoryType is invalid or HostAddress is NULL
1348 @retval EFI_UNSUPPORTED Attributes is unsupported or the memory range specified
1349 by HostAddress, Pages, and Type is not available for common buffer use.
1350 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
1354 IsaIoAllocateBuffer (
1355 IN EFI_ISA_IO_PROTOCOL
*This
,
1356 IN EFI_ALLOCATE_TYPE Type
,
1357 IN EFI_MEMORY_TYPE MemoryType
,
1359 OUT VOID
**HostAddress
,
1360 IN UINT64 Attributes
1364 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
1367 // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
1369 // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
1371 if (((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_SUPPORT_DMA
) == 0) ||
1372 ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA
) != 0)) {
1373 return EFI_UNSUPPORTED
;
1376 if (HostAddress
== NULL
) {
1377 return EFI_INVALID_PARAMETER
;
1380 if ((UINT32
)Type
>= MaxAllocateType
) {
1381 return EFI_INVALID_PARAMETER
;
1384 // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
1386 if (MemoryType
!= EfiBootServicesData
&& MemoryType
!= EfiRuntimeServicesData
) {
1387 return EFI_INVALID_PARAMETER
;
1390 if ((Attributes
& ~(EFI_ISA_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE
| EFI_ISA_IO_ATTRIBUTE_MEMORY_CACHED
)) != 0) {
1391 return EFI_UNSUPPORTED
;
1394 PhysicalAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) (ISA_MAX_MEMORY_ADDRESS
- 1);
1395 if (Type
== AllocateAddress
) {
1396 if ((UINTN
) (*HostAddress
) >= ISA_MAX_MEMORY_ADDRESS
) {
1397 return EFI_UNSUPPORTED
;
1399 PhysicalAddress
= (UINTN
) (*HostAddress
);
1403 if (Type
== AllocateAnyPages
) {
1404 Type
= AllocateMaxAddress
;
1407 Status
= gBS
->AllocatePages (Type
, MemoryType
, Pages
, &PhysicalAddress
);
1408 if (EFI_ERROR (Status
)) {
1409 REPORT_STATUS_CODE (
1410 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1411 EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
1416 *HostAddress
= (VOID
*) (UINTN
) PhysicalAddress
;
1421 Frees memory that was allocated with EFI_ISA_IO.AllocateBuffer().
1423 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1424 @param[in] Pages The number of pages to free.
1425 @param[in] HostAddress The base address of the allocated range.
1427 @retval EFI_SUCCESS The requested memory pages were freed.
1428 @retval EFI_INVALID_PARAMETER The memory was not allocated with EFI_ISA_IO.AllocateBufer().
1433 IN EFI_ISA_IO_PROTOCOL
*This
,
1435 IN VOID
*HostAddress
1441 // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
1443 // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
1445 if (((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_SUPPORT_DMA
) == 0) ||
1446 ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA
) != 0)) {
1447 return EFI_UNSUPPORTED
;
1450 Status
= gBS
->FreePages (
1451 (EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
,
1454 if (EFI_ERROR (Status
)) {
1455 REPORT_STATUS_CODE (
1456 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1457 EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR