2 The implementation for EFI_ISA_IO_PROTOCOL.
4 Copyright (c) 2006 - 2009, 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 report a error Status code
86 @param Code The error status code.
88 @return EFI_SUCCESS Success to report status code.
91 ReportErrorStatusCode (
92 EFI_STATUS_CODE_VALUE Code
95 return REPORT_STATUS_CODE (
96 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
102 Initializes an ISA I/O Instance
104 @param[in] IsaIoDevice The iso device to be initialized.
105 @param[in] IsaDeviceResourceList The resource list.
109 InitializeIsaIoInstance (
110 IN ISA_IO_DEVICE
*IsaIoDevice
,
111 IN EFI_ISA_ACPI_RESOURCE_LIST
*IsaDeviceResourceList
115 // Use the ISA IO Protocol structure template to initialize the ISA IO instance
120 sizeof (EFI_ISA_IO_PROTOCOL
)
123 IsaIoDevice
->IsaIo
.ResourceList
= IsaDeviceResourceList
;
127 Performs an ISA I/O Read Cycle
129 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
130 @param[in] Width Specifies the width of the I/O operation.
131 @param[in] Offset The offset in ISA I/O space to start the I/O operation.
132 @param[in] Count The number of I/O operations to perform.
133 @param[out] Buffer The destination buffer to store the results
135 @retval EFI_SUCCESS The data was read from the device sucessfully.
136 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
137 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
138 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
143 IN EFI_ISA_IO_PROTOCOL
*This
,
144 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
151 ISA_IO_DEVICE
*IsaIoDevice
;
153 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
156 // Verify Isa IO Access
158 Status
= IsaIoVerifyAccess (
165 if (EFI_ERROR (Status
)) {
169 Status
= IsaIoDevice
->PciIo
->Io
.Read (
171 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
172 EFI_PCI_IO_PASS_THROUGH_BAR
,
178 if (EFI_ERROR (Status
)) {
179 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
186 Performs an ISA I/O Write Cycle
188 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
189 @param[in] Width Specifies the width of the I/O operation.
190 @param[in] Offset The offset in ISA I/O space to start the I/O operation.
191 @param[in] Count The number of I/O operations to perform.
192 @param[in] Buffer The source buffer to write data from
194 @retval EFI_SUCCESS The data was writen to the device sucessfully.
195 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
196 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
197 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
202 IN EFI_ISA_IO_PROTOCOL
*This
,
203 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
210 ISA_IO_DEVICE
*IsaIoDevice
;
212 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
215 // Verify Isa IO Access
217 Status
= IsaIoVerifyAccess (
224 if (EFI_ERROR (Status
)) {
228 Status
= IsaIoDevice
->PciIo
->Io
.Write (
230 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
231 EFI_PCI_IO_PASS_THROUGH_BAR
,
237 if (EFI_ERROR (Status
)) {
238 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
245 Writes an 8-bit I/O Port
247 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
248 @param[in] Offset The offset in ISA IO space to start the IO operation.
249 @param[in] Value The data to write port.
251 @retval EFI_SUCCESS Success.
252 @retval EFI_INVALID_PARAMETER Parameter is invalid.
253 @retval EFI_UNSUPPORTED The address range specified by Offset is not valid.
254 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
258 IN EFI_ISA_IO_PROTOCOL
*This
,
264 ISA_IO_DEVICE
*IsaIoDevice
;
266 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
268 Status
= IsaIoDevice
->PciIo
->Io
.Write (
271 EFI_PCI_IO_PASS_THROUGH_BAR
,
276 if (EFI_ERROR (Status
)) {
277 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
287 Writes I/O operation base address and count number to a 8 bit I/O Port.
289 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
290 @param[in] AddrOffset The address' offset.
291 @param[in] PageOffset The page's offest.
292 @param[in] CountOffset The count's offset.
293 @param[in] BaseAddress The base address.
294 @param[in] Count The number of I/O operations to perform.
296 @retval EFI_SUCCESS Success.
297 @retval EFI_INVALID_PARAMETER Parameter is invalid.
298 @retval EFI_UNSUPPORTED The address range specified by these Offsets and Count is not valid.
299 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
303 IN EFI_ISA_IO_PROTOCOL
*This
,
304 IN UINT32 AddrOffset
,
305 IN UINT32 PageOffset
,
306 IN UINT32 CountOffset
,
307 IN UINT32 BaseAddress
,
313 Status
= WritePort (This
, AddrOffset
, (UINT8
) (BaseAddress
& 0xff));
314 if (EFI_ERROR (Status
)) {
318 Status
= WritePort (This
, AddrOffset
, (UINT8
) ((BaseAddress
>> 8) & 0xff));
319 if (EFI_ERROR (Status
)) {
323 Status
= WritePort (This
, PageOffset
, (UINT8
) ((BaseAddress
>> 16) & 0xff));
324 if (EFI_ERROR (Status
)) {
328 Status
= WritePort (This
, CountOffset
, (UINT8
) (Count
& 0xff));
329 if (EFI_ERROR (Status
)) {
333 Status
= WritePort (This
, CountOffset
, (UINT8
) ((Count
>> 8) & 0xff));
338 Unmaps a memory region for DMA
340 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
341 @param[in] Mapping The mapping value returned from EFI_ISA_IO.Map().
343 @retval EFI_SUCCESS The range was unmapped.
344 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
349 IN EFI_ISA_IO_PROTOCOL
*This
,
353 ISA_MAP_INFO
*IsaMapInfo
;
356 // Check if DMA is supported.
358 if ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_SUPPORT_DMA
) == 0) {
359 return EFI_UNSUPPORTED
;
363 // See if the Map() operation associated with this Unmap() required a mapping
364 // buffer.If a mapping buffer was not required, then this function simply
365 // returns EFI_SUCCESS.
367 if (Mapping
!= NULL
) {
369 // Get the MAP_INFO structure from Mapping
371 IsaMapInfo
= (ISA_MAP_INFO
*) Mapping
;
374 // If this is a write operation from the Agent's point of view,
375 // then copy the contents of the mapped buffer into the real buffer
376 // so the processor can read the contents of the real buffer.
378 if (IsaMapInfo
->Operation
== EfiIsaIoOperationBusMasterWrite
) {
380 (VOID
*) (UINTN
) IsaMapInfo
->HostAddress
,
381 (VOID
*) (UINTN
) IsaMapInfo
->MappedHostAddress
,
382 IsaMapInfo
->NumberOfBytes
386 // Free the mapped buffer and the MAP_INFO structure.
388 gBS
->FreePages (IsaMapInfo
->MappedHostAddress
, IsaMapInfo
->NumberOfPages
);
389 FreePool (IsaMapInfo
);
396 Flushes any posted write data to the system memory.
398 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
400 @retval EFI_SUCCESS The buffers were flushed.
401 @retval EFI_DEVICE_ERROR The buffers were not flushed due to a hardware error.
406 IN EFI_ISA_IO_PROTOCOL
*This
410 ISA_IO_DEVICE
*IsaIoDevice
;
412 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
414 Status
= IsaIoDevice
->PciIo
->Flush (IsaIoDevice
->PciIo
);
416 if (EFI_ERROR (Status
)) {
417 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
424 Verifies access to an ISA device
426 @param[in] IsaIoDevice The ISA device to be verified.
427 @param[in] Type The Access type. The input must be either IsaAccessTypeMem or IsaAccessTypeIo.
428 @param[in] Width The width of the memory operation.
429 @param[in] Count The number of memory operations to perform.
430 @param[in] Offset The offset in ISA memory space to start the memory operation.
432 @retval EFI_SUCCESS Verify success.
433 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
434 @retval EFI_UNSUPPORTED The device ont support the access type.
438 IN ISA_IO_DEVICE
*IsaIoDevice
,
439 IN ISA_ACCESS_TYPE Type
,
440 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
445 EFI_ISA_ACPI_RESOURCE
*Item
;
448 if (Width
< EfiIsaIoWidthUint8
||
449 Width
>= EfiIsaIoWidthMaximum
||
450 Width
== EfiIsaIoWidthReserved
||
451 Width
== EfiIsaIoWidthFifoReserved
||
452 Width
== EfiIsaIoWidthFillReserved
454 return EFI_INVALID_PARAMETER
;
458 // If Width is EfiIsaIoWidthFifoUintX then convert to EfiIsaIoWidthUintX
459 // If Width is EfiIsaIoWidthFillUintX then convert to EfiIsaIoWidthUintX
461 if (Width
>= EfiIsaIoWidthFifoUint8
&& Width
< EfiIsaIoWidthFifoReserved
) {
465 Width
= (EFI_ISA_IO_PROTOCOL_WIDTH
) (Width
& 0x03);
467 Status
= EFI_UNSUPPORTED
;
468 Item
= IsaIoDevice
->IsaIo
.ResourceList
->ResourceItem
;
469 while (Item
->Type
!= EfiIsaAcpiResourceEndOfList
) {
470 if ((Type
== IsaAccessTypeMem
&& Item
->Type
== EfiIsaAcpiResourceMemory
) ||
471 (Type
== IsaAccessTypeIo
&& Item
->Type
== EfiIsaAcpiResourceIo
)) {
472 if (Offset
>= Item
->StartRange
&& (Offset
+ Count
* (UINT32
)(1 << Width
)) - 1 <= Item
->EndRange
) {
476 if (Offset
>= Item
->StartRange
&& Offset
<= Item
->EndRange
) {
477 Status
= EFI_INVALID_PARAMETER
;
488 Performs an ISA Memory Read Cycle
490 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
491 @param[in] Width Specifies the width of the memory operation.
492 @param[in] Offset The offset in ISA memory space to start the memory operation.
493 @param[in] Count The number of memory operations to perform.
494 @param[out] Buffer The destination buffer to store the results
496 @retval EFI_SUCCESS The data was read from the device successfully.
497 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
498 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
499 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
504 IN EFI_ISA_IO_PROTOCOL
*This
,
505 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
512 ISA_IO_DEVICE
*IsaIoDevice
;
515 // Check if ISA memory is supported.
517 if ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY
) == 0) {
518 return EFI_UNSUPPORTED
;
521 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
524 // Verify the Isa Io Access
526 Status
= IsaIoVerifyAccess (
533 if (EFI_ERROR (Status
)) {
537 Status
= IsaIoDevice
->PciIo
->Mem
.Read (
539 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
540 EFI_PCI_IO_PASS_THROUGH_BAR
,
546 if (EFI_ERROR (Status
)) {
547 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
554 Performs an ISA Memory Write Cycle
556 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
557 @param[in] Width Specifies the width of the memory operation.
558 @param[in] Offset The offset in ISA memory space to start the memory operation.
559 @param[in] Count The number of memory operations to perform.
560 @param[in] Buffer The source buffer to write data from
562 @retval EFI_SUCCESS The data was written to the device sucessfully.
563 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
564 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
565 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
570 IN EFI_ISA_IO_PROTOCOL
*This
,
571 IN EFI_ISA_IO_PROTOCOL_WIDTH Width
,
578 ISA_IO_DEVICE
*IsaIoDevice
;
581 // Check if ISA memory is supported.
583 if ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY
) == 0) {
584 return EFI_UNSUPPORTED
;
587 IsaIoDevice
= ISA_IO_DEVICE_FROM_ISA_IO_THIS (This
);
590 // Verify Isa IO Access
592 Status
= IsaIoVerifyAccess (
599 if (EFI_ERROR (Status
)) {
603 Status
= IsaIoDevice
->PciIo
->Mem
.Write (
605 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
606 EFI_PCI_IO_PASS_THROUGH_BAR
,
612 if (EFI_ERROR (Status
)) {
613 ReportErrorStatusCode (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
)) {
691 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
698 Maps a memory region for DMA, note this implementation
699 only supports slave read/write operation to save code size.
701 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
702 @param Operation Indicates the type of DMA (slave or bus master), and if
703 the DMA operation is going to read or write to system memory.
704 @param ChannelNumber The slave channel number to use for this DMA operation.
705 If Operation and ChannelAttributes shows that this device
706 performs bus mastering DMA, then this field is ignored.
707 The legal range for this field is 0..7.
708 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
709 @param HostAddress The system memory address to map to the device.
710 @param NumberOfBytes On input the number of bytes to map. On output the number
711 of bytes that were mapped.
712 @param DeviceAddress The resulting map address for the bus master device to use
713 to access the hosts HostAddress.
714 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
716 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
717 @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.
718 @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.
719 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
720 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
723 IsaIoMapOnlySupportSlaveReadWrite (
724 IN EFI_ISA_IO_PROTOCOL
*This
,
725 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation
,
726 IN UINT8 ChannelNumber OPTIONAL
,
727 IN UINT32 ChannelAttributes
,
728 IN VOID
*HostAddress
,
729 IN OUT UINTN
*NumberOfBytes
,
730 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
735 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
736 ISA_MAP_INFO
*IsaMapInfo
;
738 UINTN MaxNumberOfBytes
;
743 UINT8 DmaChannelMode
;
745 if ((NULL
== This
) ||
746 (NULL
== HostAddress
) ||
747 (NULL
== NumberOfBytes
) ||
748 (NULL
== DeviceAddress
) ||
751 return EFI_INVALID_PARAMETER
;
755 // Initialize the return values to their defaults
760 // Make sure the Operation parameter is valid.
761 // Light IsaIo only supports two operations.
763 if (!(Operation
== EfiIsaIoOperationSlaveRead
||
764 Operation
== EfiIsaIoOperationSlaveWrite
)) {
765 return EFI_INVALID_PARAMETER
;
768 if (ChannelNumber
>= 4) {
770 // The Light IsaIo doesn't support channelNumber larger than 4.
772 return EFI_INVALID_PARAMETER
;
776 // Map the HostAddress to a DeviceAddress.
778 PhysicalAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
;
779 if ((PhysicalAddress
+ *NumberOfBytes
) > ISA_MAX_MEMORY_ADDRESS
) {
781 // Common Buffer operations can not be remapped. If the common buffer
782 // is above 16MB, then it is not possible to generate a mapping, so return
785 if (Operation
== EfiIsaIoOperationBusMasterCommonBuffer
) {
786 return EFI_UNSUPPORTED
;
789 // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
792 IsaMapInfo
= AllocatePool (sizeof (ISA_MAP_INFO
));
793 if (IsaMapInfo
== NULL
) {
795 return EFI_OUT_OF_RESOURCES
;
798 // Return a pointer to the MAP_INFO structure in Mapping
800 *Mapping
= IsaMapInfo
;
803 // Initialize the MAP_INFO structure
805 IsaMapInfo
->Operation
= Operation
;
806 IsaMapInfo
->NumberOfBytes
= *NumberOfBytes
;
807 IsaMapInfo
->NumberOfPages
= EFI_SIZE_TO_PAGES (*NumberOfBytes
);
808 IsaMapInfo
->HostAddress
= PhysicalAddress
;
809 IsaMapInfo
->MappedHostAddress
= ISA_MAX_MEMORY_ADDRESS
- 1;
812 // Allocate a buffer below 16MB to map the transfer to.
814 Status
= gBS
->AllocatePages (
817 IsaMapInfo
->NumberOfPages
,
818 &IsaMapInfo
->MappedHostAddress
820 if (EFI_ERROR (Status
)) {
821 FreePool (IsaMapInfo
);
827 // If this is a read operation from the DMA agents's point of view,
828 // then copy the contents of the real buffer into the mapped buffer
829 // so the DMA agent can read the contents of the real buffer.
831 if (Operation
== EfiIsaIoOperationSlaveRead
) {
833 (VOID
*) (UINTN
) IsaMapInfo
->MappedHostAddress
,
834 (VOID
*) (UINTN
) IsaMapInfo
->HostAddress
,
835 IsaMapInfo
->NumberOfBytes
839 // The DeviceAddress is the address of the maped buffer below 16 MB
841 *DeviceAddress
= IsaMapInfo
->MappedHostAddress
;
844 // The transfer is below 16 MB, so the DeviceAddress is simply the
847 *DeviceAddress
= PhysicalAddress
;
851 // Figure out what to program into the DMA Channel Mode Register
853 DmaMode
= (UINT8
) (B_8237_DMA_CHMODE_INCREMENT
| (ChannelNumber
& 0x03));
854 if (Operation
== EfiIsaIoOperationSlaveRead
) {
855 DmaMode
|= V_8237_DMA_CHMODE_MEM2IO
;
857 DmaMode
|= V_8237_DMA_CHMODE_IO2MEM
;
860 // We only support EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE in simplified IsaIo
862 DmaMode
|= V_8237_DMA_CHMODE_SINGLE
;
865 // A Slave DMA transfer can not cross a 64K boundary.
866 // Compute *NumberOfBytes based on this restriction.
868 MaxNumberOfBytes
= 0x10000 - ((UINT32
) (*DeviceAddress
) & 0xffff);
869 if (*NumberOfBytes
> MaxNumberOfBytes
) {
870 *NumberOfBytes
= MaxNumberOfBytes
;
873 // Compute the values to program into the BaseAddress and Count registers
874 // of the Slave DMA controller
876 BaseAddress
= (UINT32
) (*DeviceAddress
);
877 Count
= (UINT16
) (*NumberOfBytes
- 1);
879 // Program the DMA Write Single Mask Register for ChannelNumber
880 // Clear the DMA Byte Pointer Register
882 DmaMask
= R_8237_DMA_WRSMSK_CH0_3
;
883 DmaClear
= R_8237_DMA_CBPR_CH0_3
;
884 DmaChannelMode
= R_8237_DMA_CHMODE_CH0_3
;
889 (UINT8
) (B_8237_DMA_WRSMSK_CMS
| (ChannelNumber
& 0x03))
891 if (EFI_ERROR (Status
)) {
898 (UINT8
) (B_8237_DMA_WRSMSK_CMS
| (ChannelNumber
& 0x03))
900 if (EFI_ERROR (Status
)) {
904 Status
= WritePort (This
, DmaChannelMode
, DmaMode
);
905 if (EFI_ERROR (Status
)) {
909 Status
= WriteDmaPort (
911 mDmaRegisters
[ChannelNumber
].Address
,
912 mDmaRegisters
[ChannelNumber
].Page
,
913 mDmaRegisters
[ChannelNumber
].Count
,
917 if (EFI_ERROR (Status
)) {
924 (UINT8
) (ChannelNumber
& 0x03)
926 if (EFI_ERROR (Status
)) {
934 Maps a memory region for DMA. This implementation implement the
935 the full mapping support.
937 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
938 @param Operation Indicates the type of DMA (slave or bus master), and if
939 the DMA operation is going to read or write to system memory.
940 @param ChannelNumber The slave channel number to use for this DMA operation.
941 If Operation and ChannelAttributes shows that this device
942 performs bus mastering DMA, then this field is ignored.
943 The legal range for this field is 0..7.
944 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
945 @param HostAddress The system memory address to map to the device.
946 @param NumberOfBytes On input the number of bytes to map. On output the number
947 of bytes that were mapped.
948 @param DeviceAddress The resulting map address for the bus master device to use
949 to access the hosts HostAddress.
950 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
952 @retval EFI_SUCCESS - The range was mapped for the returned NumberOfBytes.
953 @retval EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined.
954 @retval EFI_UNSUPPORTED - The HostAddress can not be mapped as a common buffer.
955 @retval EFI_DEVICE_ERROR - The system hardware could not map the requested address.
956 @retval EFI_OUT_OF_RESOURCES - The memory pages could not be allocated.
959 IsaIoMapFullSupport (
960 IN EFI_ISA_IO_PROTOCOL
*This
,
961 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation
,
962 IN UINT8 ChannelNumber OPTIONAL
,
963 IN UINT32 ChannelAttributes
,
964 IN VOID
*HostAddress
,
965 IN OUT UINTN
*NumberOfBytes
,
966 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
973 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
974 ISA_MAP_INFO
*IsaMapInfo
;
976 UINTN MaxNumberOfBytes
;
981 UINT8 DmaChannelMode
;
983 if ((NULL
== This
) ||
984 (NULL
== HostAddress
) ||
985 (NULL
== NumberOfBytes
) ||
986 (NULL
== DeviceAddress
) ||
989 return EFI_INVALID_PARAMETER
;
993 // Initialize the return values to their defaults
998 // Make sure the Operation parameter is valid
1000 if (Operation
< 0 || Operation
>= EfiIsaIoOperationMaximum
) {
1001 return EFI_INVALID_PARAMETER
;
1004 if (ChannelNumber
>= 8) {
1005 return EFI_INVALID_PARAMETER
;
1009 // See if this is a Slave DMA Operation
1013 if (Operation
== EfiIsaIoOperationSlaveRead
) {
1014 Operation
= EfiIsaIoOperationBusMasterRead
;
1019 if (Operation
== EfiIsaIoOperationSlaveWrite
) {
1020 Operation
= EfiIsaIoOperationBusMasterWrite
;
1027 // Make sure that ChannelNumber is a valid channel number
1028 // Channel 4 is used to cascade, so it is illegal.
1030 if (ChannelNumber
== 4 || ChannelNumber
> 7) {
1031 return EFI_INVALID_PARAMETER
;
1034 // This implementation only support COMPATIBLE DMA Transfers
1036 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE
) == 0) {
1037 return EFI_INVALID_PARAMETER
;
1040 if ((ChannelAttributes
&
1041 (EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A
|
1042 EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B
|
1043 EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C
)) != 0) {
1044 return EFI_INVALID_PARAMETER
;
1047 if (ChannelNumber
< 4) {
1049 // If this is Channel 0..3, then the width must be 8 bit
1051 if (((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8
) == 0) ||
1052 ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16
) != 0)
1054 return EFI_INVALID_PARAMETER
;
1058 // If this is Channel 4..7, then the width must be 16 bit
1060 if (((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8
) != 0) ||
1061 ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16
) == 0)) {
1062 return EFI_INVALID_PARAMETER
;
1066 // Either Demand Mode or Single Mode must be selected, but not both
1068 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE
) != 0) {
1069 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE
) != 0) {
1070 return EFI_INVALID_PARAMETER
;
1073 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE
) == 0) {
1074 return EFI_INVALID_PARAMETER
;
1079 // Map the HostAddress to a DeviceAddress.
1081 PhysicalAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
;
1082 if ((PhysicalAddress
+*NumberOfBytes
) > ISA_MAX_MEMORY_ADDRESS
) {
1084 // Common Buffer operations can not be remapped. If the common buffer
1085 // is above 16MB, then it is not possible to generate a mapping, so return
1088 if (Operation
== EfiIsaIoOperationBusMasterCommonBuffer
) {
1089 return EFI_UNSUPPORTED
;
1092 // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
1095 IsaMapInfo
= AllocatePool (sizeof (ISA_MAP_INFO
));
1096 if (IsaMapInfo
== NULL
) {
1098 return EFI_OUT_OF_RESOURCES
;
1101 // Return a pointer to the MAP_INFO structure in Mapping
1103 *Mapping
= IsaMapInfo
;
1106 // Initialize the MAP_INFO structure
1108 IsaMapInfo
->Operation
= Operation
;
1109 IsaMapInfo
->NumberOfBytes
= *NumberOfBytes
;
1110 IsaMapInfo
->NumberOfPages
= EFI_SIZE_TO_PAGES (*NumberOfBytes
);
1111 IsaMapInfo
->HostAddress
= PhysicalAddress
;
1112 IsaMapInfo
->MappedHostAddress
= ISA_MAX_MEMORY_ADDRESS
- 1;
1115 // Allocate a buffer below 16MB to map the transfer to.
1117 Status
= gBS
->AllocatePages (
1119 EfiBootServicesData
,
1120 IsaMapInfo
->NumberOfPages
,
1121 &IsaMapInfo
->MappedHostAddress
1123 if (EFI_ERROR (Status
)) {
1124 FreePool (IsaMapInfo
);
1130 // If this is a read operation from the DMA agents's point of view,
1131 // then copy the contents of the real buffer into the mapped buffer
1132 // so the DMA agent can read the contents of the real buffer.
1134 if (Operation
== EfiIsaIoOperationBusMasterRead
) {
1136 (VOID
*) (UINTN
) IsaMapInfo
->MappedHostAddress
,
1137 (VOID
*) (UINTN
) IsaMapInfo
->HostAddress
,
1138 IsaMapInfo
->NumberOfBytes
1142 // The DeviceAddress is the address of the maped buffer below 16 MB
1144 *DeviceAddress
= IsaMapInfo
->MappedHostAddress
;
1147 // The transfer is below 16 MB, so the DeviceAddress is simply the
1150 *DeviceAddress
= PhysicalAddress
;
1153 // If this is a Bus Master operation then return
1159 // Figure out what to program into the DMA Channel Mode Register
1161 DmaMode
= (UINT8
) (B_8237_DMA_CHMODE_INCREMENT
| (ChannelNumber
& 0x03));
1163 DmaMode
|= V_8237_DMA_CHMODE_MEM2IO
;
1165 DmaMode
|= V_8237_DMA_CHMODE_IO2MEM
;
1168 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_AUTO_INITIALIZE
) != 0) {
1169 DmaMode
|= B_8237_DMA_CHMODE_AE
;
1172 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE
) != 0) {
1173 DmaMode
|= V_8237_DMA_CHMODE_DEMAND
;
1176 if ((ChannelAttributes
& EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE
) != 0) {
1177 DmaMode
|= V_8237_DMA_CHMODE_SINGLE
;
1180 // A Slave DMA transfer can not cross a 64K boundary.
1181 // Compute *NumberOfBytes based on this restriction.
1183 MaxNumberOfBytes
= 0x10000 - ((UINT32
) (*DeviceAddress
) & 0xffff);
1184 if (*NumberOfBytes
> MaxNumberOfBytes
) {
1185 *NumberOfBytes
= MaxNumberOfBytes
;
1188 // Compute the values to program into the BaseAddress and Count registers
1189 // of the Slave DMA controller
1191 if (ChannelNumber
< 4) {
1192 BaseAddress
= (UINT32
) (*DeviceAddress
);
1193 Count
= (UINT16
) (*NumberOfBytes
- 1);
1195 BaseAddress
= (UINT32
) (((UINT32
) (*DeviceAddress
) & 0xff0000) | (((UINT32
) (*DeviceAddress
) & 0xffff) >> 1));
1196 Count
= (UINT16
) ((*NumberOfBytes
- 1) >> 1);
1199 // Program the DMA Write Single Mask Register for ChannelNumber
1200 // Clear the DMA Byte Pointer Register
1202 if (ChannelNumber
< 4) {
1203 DmaMask
= R_8237_DMA_WRSMSK_CH0_3
;
1204 DmaClear
= R_8237_DMA_CBPR_CH0_3
;
1205 DmaChannelMode
= R_8237_DMA_CHMODE_CH0_3
;
1207 DmaMask
= R_8237_DMA_WRSMSK_CH4_7
;
1208 DmaClear
= R_8237_DMA_CBPR_CH4_7
;
1209 DmaChannelMode
= R_8237_DMA_CHMODE_CH4_7
;
1212 Status
= WritePort (
1215 (UINT8
) (B_8237_DMA_WRSMSK_CMS
| (ChannelNumber
& 0x03))
1217 if (EFI_ERROR (Status
)) {
1221 Status
= WritePort (
1224 (UINT8
) (B_8237_DMA_WRSMSK_CMS
| (ChannelNumber
& 0x03))
1226 if (EFI_ERROR (Status
)) {
1230 Status
= WritePort (This
, DmaChannelMode
, DmaMode
);
1231 if (EFI_ERROR (Status
)) {
1235 Status
= WriteDmaPort (
1237 mDmaRegisters
[ChannelNumber
].Address
,
1238 mDmaRegisters
[ChannelNumber
].Page
,
1239 mDmaRegisters
[ChannelNumber
].Count
,
1243 if (EFI_ERROR (Status
)) {
1247 Status
= WritePort (
1250 (UINT8
) (ChannelNumber
& 0x03)
1252 if (EFI_ERROR (Status
)) {
1260 Maps a memory region for DMA
1262 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1263 @param Operation Indicates the type of DMA (slave or bus master), and if
1264 the DMA operation is going to read or write to system memory.
1265 @param ChannelNumber The slave channel number to use for this DMA operation.
1266 If Operation and ChannelAttributes shows that this device
1267 performs bus mastering DMA, then this field is ignored.
1268 The legal range for this field is 0..7.
1269 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
1270 @param HostAddress The system memory address to map to the device.
1271 @param NumberOfBytes On input the number of bytes to map. On output the number
1272 of bytes that were mapped.
1273 @param DeviceAddress The resulting map address for the bus master device to use
1274 to access the hosts HostAddress.
1275 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
1277 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
1278 @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.
1279 @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.
1280 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
1281 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
1286 IN EFI_ISA_IO_PROTOCOL
*This
,
1287 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation
,
1288 IN UINT8 ChannelNumber OPTIONAL
,
1289 IN UINT32 ChannelAttributes
,
1290 IN VOID
*HostAddress
,
1291 IN OUT UINTN
*NumberOfBytes
,
1292 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
1297 // Check if DMA is supported.
1299 if ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_SUPPORT_DMA
) == 0) {
1300 return EFI_UNSUPPORTED
;
1303 // Set Feature Flag PcdIsaBusSupportBusMaster to FALSE to disable support for
1306 // So we just return EFI_UNSUPPORTED for these functions.
1308 if ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA
) != 0) {
1309 return IsaIoMapOnlySupportSlaveReadWrite (
1321 return IsaIoMapFullSupport (
1335 Allocates pages that are suitable for an EfiIsaIoOperationBusMasterCommonBuffer mapping.
1337 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1338 @param[in] Type The type allocation to perform.
1339 @param[in] MemoryType The type of memory to allocate.
1340 @param[in] Pages The number of pages to allocate.
1341 @param[out] HostAddress A pointer to store the base address of the allocated range.
1342 @param[in] Attributes The requested bit mask of attributes for the allocated range.
1344 @retval EFI_SUCCESS The requested memory pages were allocated.
1345 @retval EFI_INVALID_PARAMETER Type is invalid or MemoryType is invalid or HostAddress is NULL
1346 @retval EFI_UNSUPPORTED Attributes is unsupported or the memory range specified
1347 by HostAddress, Pages, and Type is not available for common buffer use.
1348 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
1352 IsaIoAllocateBuffer (
1353 IN EFI_ISA_IO_PROTOCOL
*This
,
1354 IN EFI_ALLOCATE_TYPE Type
,
1355 IN EFI_MEMORY_TYPE MemoryType
,
1357 OUT VOID
**HostAddress
,
1358 IN UINT64 Attributes
1362 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
1365 // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
1367 // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
1369 if (((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_SUPPORT_DMA
) == 0) ||
1370 ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA
) != 0)) {
1371 return EFI_UNSUPPORTED
;
1374 if (HostAddress
== NULL
) {
1375 return EFI_INVALID_PARAMETER
;
1378 if (Type
< AllocateAnyPages
|| Type
>= MaxAllocateType
) {
1379 return EFI_INVALID_PARAMETER
;
1382 // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
1384 if (MemoryType
!= EfiBootServicesData
&& MemoryType
!= EfiRuntimeServicesData
) {
1385 return EFI_INVALID_PARAMETER
;
1388 if ((Attributes
& ~(EFI_ISA_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE
| EFI_ISA_IO_ATTRIBUTE_MEMORY_CACHED
)) != 0) {
1389 return EFI_UNSUPPORTED
;
1392 PhysicalAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) (ISA_MAX_MEMORY_ADDRESS
- 1);
1393 if (Type
== AllocateAddress
) {
1394 if ((UINTN
) (*HostAddress
) >= ISA_MAX_MEMORY_ADDRESS
) {
1395 return EFI_UNSUPPORTED
;
1397 PhysicalAddress
= (UINTN
) (*HostAddress
);
1401 if (Type
== AllocateAnyPages
) {
1402 Type
= AllocateMaxAddress
;
1405 Status
= gBS
->AllocatePages (Type
, MemoryType
, Pages
, &PhysicalAddress
);
1406 if (EFI_ERROR (Status
)) {
1407 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);
1411 *HostAddress
= (VOID
*) (UINTN
) PhysicalAddress
;
1416 Frees memory that was allocated with EFI_ISA_IO.AllocateBuffer().
1418 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1419 @param[in] Pages The number of pages to free.
1420 @param[in] HostAddress The base address of the allocated range.
1422 @retval EFI_SUCCESS The requested memory pages were freed.
1423 @retval EFI_INVALID_PARAMETER The memory was not allocated with EFI_ISA_IO.AllocateBufer().
1428 IN EFI_ISA_IO_PROTOCOL
*This
,
1430 IN VOID
*HostAddress
1436 // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
1438 // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
1440 if (((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_SUPPORT_DMA
) == 0) ||
1441 ((PcdGet8 (PcdIsaBusSupportedFeatures
) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA
) != 0)) {
1442 return EFI_UNSUPPORTED
;
1445 Status
= gBS
->FreePages (
1446 (EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
,
1449 if (EFI_ERROR (Status
)) {
1450 ReportErrorStatusCode (EFI_IO_BUS_LPC
| EFI_IOB_EC_CONTROLLER_ERROR
);