]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIo.c
IntelFrameworkModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Isa / IsaIoDxe / IsaIo.c
1 /** @file
2 The implementation for EFI_ISA_IO_PROTOCOL.
3
4 Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "IsaIo.h"
10
11 //
12 // Module Variables
13 //
14 EFI_ISA_IO_PROTOCOL mIsaIoInterface = {
15 {
16 IsaIoMemRead,
17 IsaIoMemWrite
18 },
19 {
20 IsaIoIoRead,
21 IsaIoIoWrite
22 },
23 IsaIoCopyMem,
24 IsaIoMap,
25 IsaIoUnmap,
26 IsaIoAllocateBuffer,
27 IsaIoFreeBuffer,
28 IsaIoFlush,
29 NULL,
30 0,
31 NULL
32 };
33
34 EFI_ISA_DMA_REGISTERS mDmaRegisters[8] = {
35 {
36 0x00,
37 0x87,
38 0x01
39 },
40 {
41 0x02,
42 0x83,
43 0x03
44 },
45 {
46 0x04,
47 0x81,
48 0x05
49 },
50 {
51 0x06,
52 0x82,
53 0x07
54 },
55 {
56 0x00,
57 0x00,
58 0x00
59 }, // Channel 4 is invalid
60 {
61 0xC4,
62 0x8B,
63 0xC6
64 },
65 {
66 0xC8,
67 0x89,
68 0xCA
69 },
70 {
71 0xCC,
72 0x8A,
73 0xCE
74 },
75 };
76
77 /**
78 Verifies access to an ISA device
79
80 @param[in] IsaIoDevice The ISA device to be verified.
81 @param[in] Type The Access type. The input must be either IsaAccessTypeMem or IsaAccessTypeIo.
82 @param[in] Width The width of the memory operation.
83 @param[in] Count The number of memory operations to perform.
84 @param[in] Offset The offset in ISA memory space to start the memory operation.
85
86 @retval EFI_SUCCESS Verify success.
87 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
88 @retval EFI_UNSUPPORTED The device ont support the access type.
89 **/
90 EFI_STATUS
91 IsaIoVerifyAccess (
92 IN ISA_IO_DEVICE *IsaIoDevice,
93 IN ISA_ACCESS_TYPE Type,
94 IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
95 IN UINTN Count,
96 IN UINT32 Offset
97 )
98 {
99 EFI_ISA_ACPI_RESOURCE *Item;
100 EFI_STATUS Status;
101
102 if ((UINT32)Width >= EfiIsaIoWidthMaximum ||
103 Width == EfiIsaIoWidthReserved ||
104 Width == EfiIsaIoWidthFifoReserved ||
105 Width == EfiIsaIoWidthFillReserved
106 ) {
107 return EFI_INVALID_PARAMETER;
108 }
109
110 //
111 // If Width is EfiIsaIoWidthFifoUintX then convert to EfiIsaIoWidthUintX
112 // If Width is EfiIsaIoWidthFillUintX then convert to EfiIsaIoWidthUintX
113 //
114 if (Width >= EfiIsaIoWidthFifoUint8 && Width < EfiIsaIoWidthFifoReserved) {
115 Count = 1;
116 }
117
118 Width = (EFI_ISA_IO_PROTOCOL_WIDTH) (Width & 0x03);
119
120 Status = EFI_UNSUPPORTED;
121 Item = IsaIoDevice->IsaIo.ResourceList->ResourceItem;
122 while (Item->Type != EfiIsaAcpiResourceEndOfList) {
123 if ((Type == IsaAccessTypeMem && Item->Type == EfiIsaAcpiResourceMemory) ||
124 (Type == IsaAccessTypeIo && Item->Type == EfiIsaAcpiResourceIo)) {
125 if (Offset >= Item->StartRange && (Offset + Count * (UINT32)(1 << Width)) - 1 <= Item->EndRange) {
126 return EFI_SUCCESS;
127 }
128
129 if (Offset >= Item->StartRange && Offset <= Item->EndRange) {
130 Status = EFI_INVALID_PARAMETER;
131 }
132 }
133
134 Item++;
135 }
136
137 return Status;
138 }
139
140 /**
141 Convert the IO Information in ACPI descriptor to IO ISA Attribute.
142
143 @param[in] Information The IO Information in ACPI descriptor
144
145 @return UINT32 The IO ISA Attribute
146 **/
147 UINT32
148 IsaIoAttribute (
149 IN UINT8 Information
150 )
151 {
152 UINT32 Attribute;
153
154 Attribute = 0;
155
156 switch (Information & EFI_ACPI_IO_DECODE_MASK) {
157 case EFI_ACPI_IO_DECODE_16_BIT:
158 Attribute |= EFI_ISA_ACPI_IO_DECODE_16_BITS;
159 break;
160
161 case EFI_ACPI_IO_DECODE_10_BIT:
162 Attribute |= EFI_ISA_ACPI_IO_DECODE_10_BITS;
163 break;
164 }
165
166 return Attribute;
167 }
168
169 /**
170 Convert the IRQ Information in ACPI descriptor to IRQ ISA Attribute.
171
172 @param[in] Information The IRQ Information in ACPI descriptor
173
174 @return UINT32 The IRQ ISA Attribute
175 **/
176 UINT32
177 IsaIrqAttribute (
178 IN UINT8 Information
179 )
180 {
181 UINT32 Attribute;
182
183 Attribute = 0;
184
185 if ((Information & EFI_ACPI_IRQ_POLARITY_MASK) == EFI_ACPI_IRQ_HIGH_TRUE) {
186 if ((Information & EFI_ACPI_IRQ_MODE) == EFI_ACPI_IRQ_LEVEL_TRIGGERED) {
187 Attribute = EFI_ISA_ACPI_IRQ_TYPE_HIGH_TRUE_LEVEL_SENSITIVE;
188 } else {
189 Attribute = EFI_ISA_ACPI_IRQ_TYPE_HIGH_TRUE_EDGE_SENSITIVE;
190 }
191 } else {
192 if ((Information & EFI_ACPI_IRQ_MODE) == EFI_ACPI_IRQ_LEVEL_TRIGGERED) {
193 Attribute = EFI_ISA_ACPI_IRQ_TYPE_LOW_TRUE_LEVEL_SENSITIVE;
194 } else {
195 Attribute = EFI_ISA_ACPI_IRQ_TYPE_LOW_TRUE_EDGE_SENSITIVE;
196 }
197 }
198 return Attribute;
199 }
200
201 /**
202 Convert the Memory Information in ACPI descriptor to Memory ISA Attribute.
203
204 @param[in] Information The Memory Information in ACPI descriptor
205
206 @return UINT32 The Memory ISA Attribute
207 **/
208 UINT32
209 IsaMemoryAttribute (
210 IN UINT8 Information
211 )
212 {
213 UINT32 Attribute;
214
215 Attribute = 0;
216
217 switch (Information & EFI_ACPI_MEMORY_WRITE_STATUS_MASK) {
218 case EFI_ACPI_MEMORY_WRITABLE:
219 Attribute |= EFI_ISA_ACPI_MEMORY_WRITEABLE;
220 break;
221 }
222
223 return Attribute;
224 }
225
226 /**
227 Convert the DMA Information in ACPI descriptor to DMA ISA Attribute.
228
229 @param[in] Information The DMA Information in ACPI descriptor
230
231 @return UINT32 The DMA ISA Attribute
232 **/
233 UINT32
234 IsaDmaAttribute (
235 IN UINT8 Information
236 )
237 {
238 UINT32 Attribute;
239
240 Attribute = EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE;
241
242 switch (Information & EFI_ACPI_DMA_SPEED_TYPE_MASK) {
243 case EFI_ACPI_DMA_SPEED_TYPE_COMPATIBILITY:
244 Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE;
245 break;
246 case EFI_ACPI_DMA_SPEED_TYPE_A:
247 Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A;
248 break;
249 case EFI_ACPI_DMA_SPEED_TYPE_B:
250 Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B;
251 break;
252 case EFI_ACPI_DMA_SPEED_TYPE_F:
253 Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C;
254 break;
255 }
256
257 switch (Information & EFI_ACPI_DMA_TRANSFER_TYPE_MASK) {
258 case EFI_ACPI_DMA_TRANSFER_TYPE_8_BIT:
259 Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8;
260 break;
261 case EFI_ACPI_DMA_TRANSFER_TYPE_16_BIT:
262 Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16;
263 break;
264 }
265
266 return Attribute;
267 }
268
269 /**
270 Convert the ACPI resource descriptor to ISA resource descriptor.
271
272 @param[in] AcpiResource Pointer to the ACPI resource descriptor
273 @param[out] IsaResource The optional pointer to the buffer to
274 store the converted ISA resource descriptor
275
276 @return UINTN Number of ISA resource descriptor needed
277 **/
278 UINTN
279 AcpiResourceToIsaResource (
280 IN ACPI_RESOURCE_HEADER_PTR AcpiResource,
281 OUT EFI_ISA_ACPI_RESOURCE *IsaResource OPTIONAL
282 )
283 {
284 UINT32 Index;
285 UINTN Count;
286 UINT32 LastIndex;
287 EFI_ACPI_IO_PORT_DESCRIPTOR *Io;
288 EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *FixedIo;
289 EFI_ACPI_IRQ_DESCRIPTOR *Irq;
290 EFI_ACPI_DMA_DESCRIPTOR *Dma;
291 EFI_ACPI_32_BIT_MEMORY_RANGE_DESCRIPTOR *Memory;
292 EFI_ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR *FixedMemory;
293
294 Count = 0;
295 LastIndex = 0;
296
297 switch (AcpiResource.SmallHeader->Byte) {
298 case ACPI_DMA_DESCRIPTOR:
299 Dma = (EFI_ACPI_DMA_DESCRIPTOR *) AcpiResource.SmallHeader;
300 for (Index = 0; Index < sizeof (Dma->ChannelMask) * 8; Index++) {
301 if (Dma->ChannelMask & (1 << Index)) {
302 if ((Count > 0) && (LastIndex + 1 == Index)) {
303 if (IsaResource != NULL) {
304 IsaResource[Count - 1].EndRange ++;
305 }
306 } else {
307 if (IsaResource != NULL) {
308 IsaResource[Count].Type = EfiIsaAcpiResourceDma;
309 IsaResource[Count].Attribute = IsaDmaAttribute (Dma->Information);
310 IsaResource[Count].StartRange = Index;
311 IsaResource[Count].EndRange = Index;
312 }
313 Count ++;
314 }
315
316 LastIndex = Index;
317 }
318 }
319 break;
320
321 case ACPI_IO_PORT_DESCRIPTOR:
322 Io = (EFI_ACPI_IO_PORT_DESCRIPTOR *) AcpiResource.SmallHeader;
323 if (Io->Length != 0) {
324 if (IsaResource != NULL) {
325 IsaResource[Count].Type = EfiIsaAcpiResourceIo;
326 IsaResource[Count].Attribute = IsaIoAttribute (Io->Information);
327 IsaResource[Count].StartRange = Io->BaseAddressMin;
328 IsaResource[Count].EndRange = Io->BaseAddressMin + Io->Length - 1;
329 }
330 Count ++;
331 }
332 break;
333
334 case ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR:
335 FixedIo = (EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *) AcpiResource.SmallHeader;
336 if (FixedIo->Length != 0) {
337 if (IsaResource != NULL) {
338 IsaResource[Count].Type = EfiIsaAcpiResourceIo;
339 IsaResource[Count].Attribute = EFI_ISA_ACPI_IO_DECODE_10_BITS;
340 IsaResource[Count].StartRange = FixedIo->BaseAddress;
341 IsaResource[Count].EndRange = FixedIo->BaseAddress + FixedIo->Length - 1;
342 }
343 Count ++;
344 }
345 break;
346
347 case ACPI_IRQ_DESCRIPTOR:
348 case ACPI_IRQ_NOFLAG_DESCRIPTOR:
349 Irq = (EFI_ACPI_IRQ_DESCRIPTOR *) AcpiResource.SmallHeader;
350 for (Index = 0; Index < sizeof (Irq->Mask) * 8; Index++) {
351 if (Irq->Mask & (1 << Index)) {
352 if ((Count > 0) && (LastIndex + 1 == Index)) {
353 if (IsaResource != NULL) {
354 IsaResource[Count - 1].EndRange ++;
355 }
356 } else {
357 if (IsaResource != NULL) {
358 IsaResource[Count].Type = EfiIsaAcpiResourceInterrupt;
359 if (AcpiResource.SmallHeader->Byte == ACPI_IRQ_DESCRIPTOR) {
360 IsaResource[Count].Attribute = IsaIrqAttribute (Irq->Information);
361 } else {
362 IsaResource[Count].Attribute = EFI_ISA_ACPI_IRQ_TYPE_HIGH_TRUE_EDGE_SENSITIVE;
363 }
364 IsaResource[Count].StartRange = Index;
365 IsaResource[Count].EndRange = Index;
366 }
367 Count++;
368 }
369
370 LastIndex = Index;
371 }
372 }
373 break;
374
375 case ACPI_32_BIT_MEMORY_RANGE_DESCRIPTOR:
376 Memory = (EFI_ACPI_32_BIT_MEMORY_RANGE_DESCRIPTOR *) AcpiResource.LargeHeader;
377 if (Memory->Length != 0) {
378 if (IsaResource != NULL) {
379 IsaResource[Count].Type = EfiIsaAcpiResourceMemory;
380 IsaResource[Count].Attribute = IsaMemoryAttribute (Memory->Information);
381 IsaResource[Count].StartRange = Memory->BaseAddressMin;
382 IsaResource[Count].EndRange = Memory->BaseAddressMin + Memory->Length - 1;
383 }
384 Count ++;
385 }
386 break;
387
388 case ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR:
389 FixedMemory = (EFI_ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR *) AcpiResource.LargeHeader;
390 if (FixedMemory->Length != 0) {
391 if (IsaResource != NULL) {
392 IsaResource[Count].Type = EfiIsaAcpiResourceMemory;
393 IsaResource[Count].Attribute = IsaMemoryAttribute (FixedMemory->Information);
394 IsaResource[Count].StartRange = FixedMemory->BaseAddress;
395 IsaResource[Count].EndRange = FixedMemory->BaseAddress + FixedMemory->Length - 1;
396 }
397 Count ++;
398 }
399 break;
400
401 case ACPI_END_TAG_DESCRIPTOR:
402 if (IsaResource != NULL) {
403 IsaResource[Count].Type = EfiIsaAcpiResourceEndOfList;
404 IsaResource[Count].Attribute = 0;
405 IsaResource[Count].StartRange = 0;
406 IsaResource[Count].EndRange = 0;
407 }
408 Count ++;
409 break;
410 }
411
412 return Count;
413 }
414
415 /**
416 Initializes an ISA I/O Instance
417
418 @param[in] IsaIoDevice The isa device to be initialized.
419 @param[in] DevicePath The device path of the isa device.
420 @param[in] Resources The ACPI resource list.
421
422 **/
423 VOID
424 InitializeIsaIoInstance (
425 IN ISA_IO_DEVICE *IsaIoDevice,
426 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
427 IN ACPI_RESOURCE_HEADER_PTR Resources
428 )
429 {
430 UINTN Index;
431 ACPI_HID_DEVICE_PATH *AcpiNode;
432 ACPI_RESOURCE_HEADER_PTR ResourcePtr;
433
434 //
435 // Use the ISA IO Protocol structure template to initialize the ISA IO instance
436 //
437 CopyMem (
438 &IsaIoDevice->IsaIo,
439 &mIsaIoInterface,
440 sizeof (EFI_ISA_IO_PROTOCOL)
441 );
442
443 //
444 // Count the resources including the ACPI End Tag
445 //
446 ResourcePtr = Resources;
447 Index = 0;
448 while (ResourcePtr.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) {
449
450 Index += AcpiResourceToIsaResource (ResourcePtr, NULL);
451
452 if (ResourcePtr.SmallHeader->Bits.Type == 0) {
453 ResourcePtr.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) ResourcePtr.SmallHeader
454 + ResourcePtr.SmallHeader->Bits.Length
455 + sizeof (*ResourcePtr.SmallHeader));
456 } else {
457 ResourcePtr.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) ResourcePtr.LargeHeader
458 + ResourcePtr.LargeHeader->Length
459 + sizeof (*ResourcePtr.LargeHeader));
460 }
461
462 }
463 //
464 // Get the Isa Resource count for ACPI End Tag
465 //
466 Index += AcpiResourceToIsaResource (ResourcePtr, NULL);
467
468 //
469 // Initialize the ResourceList
470 //
471 IsaIoDevice->IsaIo.ResourceList = AllocatePool (sizeof (EFI_ISA_ACPI_RESOURCE_LIST) + Index * sizeof (EFI_ISA_ACPI_RESOURCE));
472 ASSERT (IsaIoDevice->IsaIo.ResourceList != NULL);
473 IsaIoDevice->IsaIo.ResourceList->ResourceItem = (EFI_ISA_ACPI_RESOURCE *) (IsaIoDevice->IsaIo.ResourceList + 1);
474
475 AcpiNode = (ACPI_HID_DEVICE_PATH *) ((UINT8 *) DevicePath + GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH - sizeof (ACPI_HID_DEVICE_PATH));
476 IsaIoDevice->IsaIo.ResourceList->Device.HID = AcpiNode->HID;
477 IsaIoDevice->IsaIo.ResourceList->Device.UID = AcpiNode->UID;
478
479 ResourcePtr = Resources;
480 Index = 0;
481 while (ResourcePtr.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) {
482
483 Index += AcpiResourceToIsaResource (ResourcePtr, &IsaIoDevice->IsaIo.ResourceList->ResourceItem[Index]);
484
485 if (ResourcePtr.SmallHeader->Bits.Type == 0) {
486 ResourcePtr.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) ResourcePtr.SmallHeader
487 + ResourcePtr.SmallHeader->Bits.Length
488 + sizeof (*ResourcePtr.SmallHeader));
489 } else {
490 ResourcePtr.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) ResourcePtr.LargeHeader
491 + ResourcePtr.LargeHeader->Length
492 + sizeof (*ResourcePtr.LargeHeader));
493 }
494 }
495
496 //
497 // Convert the ACPI End Tag
498 //
499 AcpiResourceToIsaResource (ResourcePtr, &IsaIoDevice->IsaIo.ResourceList->ResourceItem[Index]);
500 }
501
502 /**
503 Performs an ISA I/O Read Cycle
504
505 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
506 @param[in] Width Specifies the width of the I/O operation.
507 @param[in] Offset The offset in ISA I/O space to start the I/O operation.
508 @param[in] Count The number of I/O operations to perform.
509 @param[out] Buffer The destination buffer to store the results
510
511 @retval EFI_SUCCESS The data was read from the device sucessfully.
512 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
513 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
514 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
515 **/
516 EFI_STATUS
517 EFIAPI
518 IsaIoIoRead (
519 IN EFI_ISA_IO_PROTOCOL *This,
520 IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
521 IN UINT32 Offset,
522 IN UINTN Count,
523 OUT VOID *Buffer
524 )
525 {
526 EFI_STATUS Status;
527 ISA_IO_DEVICE *IsaIoDevice;
528
529 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
530
531 //
532 // Verify Isa IO Access
533 //
534 Status = IsaIoVerifyAccess (
535 IsaIoDevice,
536 IsaAccessTypeIo,
537 Width,
538 Count,
539 Offset
540 );
541 if (EFI_ERROR (Status)) {
542 return Status;
543 }
544
545 Status = IsaIoDevice->PciIo->Io.Read (
546 IsaIoDevice->PciIo,
547 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
548 EFI_PCI_IO_PASS_THROUGH_BAR,
549 Offset,
550 Count,
551 Buffer
552 );
553
554 if (EFI_ERROR (Status)) {
555 REPORT_STATUS_CODE (
556 EFI_ERROR_CODE | EFI_ERROR_MINOR,
557 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
558 );
559 }
560
561 return Status;
562 }
563
564 /**
565 Performs an ISA I/O Write Cycle
566
567 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
568 @param[in] Width Specifies the width of the I/O operation.
569 @param[in] Offset The offset in ISA I/O space to start the I/O operation.
570 @param[in] Count The number of I/O operations to perform.
571 @param[in] Buffer The source buffer to write data from
572
573 @retval EFI_SUCCESS The data was writen to the device sucessfully.
574 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
575 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
576 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
577 **/
578 EFI_STATUS
579 EFIAPI
580 IsaIoIoWrite (
581 IN EFI_ISA_IO_PROTOCOL *This,
582 IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
583 IN UINT32 Offset,
584 IN UINTN Count,
585 IN VOID *Buffer
586 )
587 {
588 EFI_STATUS Status;
589 ISA_IO_DEVICE *IsaIoDevice;
590
591 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
592
593 //
594 // Verify Isa IO Access
595 //
596 Status = IsaIoVerifyAccess (
597 IsaIoDevice,
598 IsaAccessTypeIo,
599 Width,
600 Count,
601 Offset
602 );
603 if (EFI_ERROR (Status)) {
604 return Status;
605 }
606
607 Status = IsaIoDevice->PciIo->Io.Write (
608 IsaIoDevice->PciIo,
609 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
610 EFI_PCI_IO_PASS_THROUGH_BAR,
611 Offset,
612 Count,
613 Buffer
614 );
615
616 if (EFI_ERROR (Status)) {
617 REPORT_STATUS_CODE (
618 EFI_ERROR_CODE | EFI_ERROR_MINOR,
619 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
620 );
621 }
622
623 return Status;
624 }
625
626 /**
627 Writes an 8-bit I/O Port
628
629 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
630 @param[in] Offset The offset in ISA IO space to start the IO operation.
631 @param[in] Value The data to write port.
632
633 @retval EFI_SUCCESS Success.
634 @retval EFI_INVALID_PARAMETER Parameter is invalid.
635 @retval EFI_UNSUPPORTED The address range specified by Offset is not valid.
636 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
637 **/
638 EFI_STATUS
639 WritePort (
640 IN EFI_ISA_IO_PROTOCOL *This,
641 IN UINT32 Offset,
642 IN UINT8 Value
643 )
644 {
645 EFI_STATUS Status;
646 ISA_IO_DEVICE *IsaIoDevice;
647
648 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
649
650 Status = IsaIoDevice->PciIo->Io.Write (
651 IsaIoDevice->PciIo,
652 EfiPciIoWidthUint8,
653 EFI_PCI_IO_PASS_THROUGH_BAR,
654 Offset,
655 1,
656 &Value
657 );
658 if (EFI_ERROR (Status)) {
659 REPORT_STATUS_CODE (
660 EFI_ERROR_CODE | EFI_ERROR_MINOR,
661 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
662 );
663 return Status;
664 }
665
666 //
667 // Wait for 50 microseconds to take affect.
668 //
669 gBS->Stall (50);
670
671 return EFI_SUCCESS;
672 }
673
674 /**
675 Writes I/O operation base address and count number to a 8 bit I/O Port.
676
677 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
678 @param[in] AddrOffset The address' offset.
679 @param[in] PageOffset The page's offest.
680 @param[in] CountOffset The count's offset.
681 @param[in] BaseAddress The base address.
682 @param[in] Count The number of I/O operations to perform.
683
684 @retval EFI_SUCCESS Success.
685 @retval EFI_INVALID_PARAMETER Parameter is invalid.
686 @retval EFI_UNSUPPORTED The address range specified by these Offsets and Count is not valid.
687 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
688 **/
689 EFI_STATUS
690 WriteDmaPort (
691 IN EFI_ISA_IO_PROTOCOL *This,
692 IN UINT32 AddrOffset,
693 IN UINT32 PageOffset,
694 IN UINT32 CountOffset,
695 IN UINT32 BaseAddress,
696 IN UINT16 Count
697 )
698 {
699 EFI_STATUS Status;
700
701 Status = WritePort (This, AddrOffset, (UINT8) (BaseAddress & 0xff));
702 if (EFI_ERROR (Status)) {
703 return Status;
704 }
705
706 Status = WritePort (This, AddrOffset, (UINT8) ((BaseAddress >> 8) & 0xff));
707 if (EFI_ERROR (Status)) {
708 return Status;
709 }
710
711 Status = WritePort (This, PageOffset, (UINT8) ((BaseAddress >> 16) & 0xff));
712 if (EFI_ERROR (Status)) {
713 return Status;
714 }
715
716 Status = WritePort (This, CountOffset, (UINT8) (Count & 0xff));
717 if (EFI_ERROR (Status)) {
718 return Status;
719 }
720
721 Status = WritePort (This, CountOffset, (UINT8) ((Count >> 8) & 0xff));
722 return Status;
723 }
724
725 /**
726 Unmaps a memory region for DMA
727
728 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
729 @param[in] Mapping The mapping value returned from EFI_ISA_IO.Map().
730
731 @retval EFI_SUCCESS The range was unmapped.
732 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
733 **/
734 EFI_STATUS
735 EFIAPI
736 IsaIoUnmap (
737 IN EFI_ISA_IO_PROTOCOL *This,
738 IN VOID *Mapping
739 )
740 {
741 ISA_MAP_INFO *IsaMapInfo;
742
743 //
744 // Check if DMA is supported.
745 //
746 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) {
747 return EFI_UNSUPPORTED;
748 }
749
750 //
751 // See if the Map() operation associated with this Unmap() required a mapping
752 // buffer.If a mapping buffer was not required, then this function simply
753 // returns EFI_SUCCESS.
754 //
755 if (Mapping != NULL) {
756 //
757 // Get the MAP_INFO structure from Mapping
758 //
759 IsaMapInfo = (ISA_MAP_INFO *) Mapping;
760
761 //
762 // If this is a write operation from the Agent's point of view,
763 // then copy the contents of the mapped buffer into the real buffer
764 // so the processor can read the contents of the real buffer.
765 //
766 if (IsaMapInfo->Operation == EfiIsaIoOperationBusMasterWrite) {
767 CopyMem (
768 (VOID *) (UINTN) IsaMapInfo->HostAddress,
769 (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,
770 IsaMapInfo->NumberOfBytes
771 );
772 }
773 //
774 // Free the mapped buffer and the MAP_INFO structure.
775 //
776 gBS->FreePages (IsaMapInfo->MappedHostAddress, IsaMapInfo->NumberOfPages);
777 FreePool (IsaMapInfo);
778 }
779
780 return EFI_SUCCESS;
781 }
782
783 /**
784 Flushes any posted write data to the system memory.
785
786 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
787
788 @retval EFI_SUCCESS The buffers were flushed.
789 @retval EFI_DEVICE_ERROR The buffers were not flushed due to a hardware error.
790 **/
791 EFI_STATUS
792 EFIAPI
793 IsaIoFlush (
794 IN EFI_ISA_IO_PROTOCOL *This
795 )
796 {
797 EFI_STATUS Status;
798 ISA_IO_DEVICE *IsaIoDevice;
799
800 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
801
802 Status = IsaIoDevice->PciIo->Flush (IsaIoDevice->PciIo);
803
804 if (EFI_ERROR (Status)) {
805 REPORT_STATUS_CODE (
806 EFI_ERROR_CODE | EFI_ERROR_MINOR,
807 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
808 );
809 }
810
811 return Status;
812 }
813
814 /**
815 Performs an ISA Memory Read Cycle
816
817 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
818 @param[in] Width Specifies the width of the memory operation.
819 @param[in] Offset The offset in ISA memory space to start the memory operation.
820 @param[in] Count The number of memory operations to perform.
821 @param[out] Buffer The destination buffer to store the results
822
823 @retval EFI_SUCCESS The data was read from the device successfully.
824 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
825 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
826 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
827 **/
828 EFI_STATUS
829 EFIAPI
830 IsaIoMemRead (
831 IN EFI_ISA_IO_PROTOCOL *This,
832 IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
833 IN UINT32 Offset,
834 IN UINTN Count,
835 OUT VOID *Buffer
836 )
837 {
838 EFI_STATUS Status;
839 ISA_IO_DEVICE *IsaIoDevice;
840
841 //
842 // Check if ISA memory is supported.
843 //
844 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {
845 return EFI_UNSUPPORTED;
846 }
847
848 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
849
850 //
851 // Verify the Isa Io Access
852 //
853 Status = IsaIoVerifyAccess (
854 IsaIoDevice,
855 IsaAccessTypeMem,
856 Width,
857 Count,
858 Offset
859 );
860 if (EFI_ERROR (Status)) {
861 return Status;
862 }
863
864 Status = IsaIoDevice->PciIo->Mem.Read (
865 IsaIoDevice->PciIo,
866 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
867 EFI_PCI_IO_PASS_THROUGH_BAR,
868 Offset,
869 Count,
870 Buffer
871 );
872
873 if (EFI_ERROR (Status)) {
874 REPORT_STATUS_CODE (
875 EFI_ERROR_CODE | EFI_ERROR_MINOR,
876 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
877 );
878 }
879
880 return Status;
881 }
882
883 /**
884 Performs an ISA Memory Write Cycle
885
886 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
887 @param[in] Width Specifies the width of the memory operation.
888 @param[in] Offset The offset in ISA memory space to start the memory operation.
889 @param[in] Count The number of memory operations to perform.
890 @param[in] Buffer The source buffer to write data from
891
892 @retval EFI_SUCCESS The data was written to the device sucessfully.
893 @retval EFI_UNSUPPORTED The Offset is not valid for this device.
894 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
895 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
896 **/
897 EFI_STATUS
898 EFIAPI
899 IsaIoMemWrite (
900 IN EFI_ISA_IO_PROTOCOL *This,
901 IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
902 IN UINT32 Offset,
903 IN UINTN Count,
904 IN VOID *Buffer
905 )
906 {
907 EFI_STATUS Status;
908 ISA_IO_DEVICE *IsaIoDevice;
909
910 //
911 // Check if ISA memory is supported.
912 //
913 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {
914 return EFI_UNSUPPORTED;
915 }
916
917 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
918
919 //
920 // Verify Isa IO Access
921 //
922 Status = IsaIoVerifyAccess (
923 IsaIoDevice,
924 IsaAccessTypeMem,
925 Width,
926 Count,
927 Offset
928 );
929 if (EFI_ERROR (Status)) {
930 return Status;
931 }
932
933 Status = IsaIoDevice->PciIo->Mem.Write (
934 IsaIoDevice->PciIo,
935 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
936 EFI_PCI_IO_PASS_THROUGH_BAR,
937 Offset,
938 Count,
939 Buffer
940 );
941
942 if (EFI_ERROR (Status)) {
943 REPORT_STATUS_CODE (
944 EFI_ERROR_CODE | EFI_ERROR_MINOR,
945 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
946 );
947 }
948
949 return Status;
950 }
951
952 /**
953 Copy one region of ISA memory space to another region of ISA memory space on the ISA controller.
954
955 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
956 @param[in] Width Specifies the width of the memory copy operation.
957 @param[in] DestOffset The offset of the destination
958 @param[in] SrcOffset The offset of the source
959 @param[in] Count The number of memory copy operations to perform
960
961 @retval EFI_SUCCESS The data was copied sucessfully.
962 @retval EFI_UNSUPPORTED The DestOffset or SrcOffset is not valid for this device.
963 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
964 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
965 **/
966 EFI_STATUS
967 EFIAPI
968 IsaIoCopyMem (
969 IN EFI_ISA_IO_PROTOCOL *This,
970 IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
971 IN UINT32 DestOffset,
972 IN UINT32 SrcOffset,
973 IN UINTN Count
974 )
975 {
976 EFI_STATUS Status;
977 ISA_IO_DEVICE *IsaIoDevice;
978
979 //
980 // Check if ISA memory is supported.
981 //
982 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {
983 return EFI_UNSUPPORTED;
984 }
985
986 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
987
988 //
989 // Verify Isa IO Access for destination and source
990 //
991 Status = IsaIoVerifyAccess (
992 IsaIoDevice,
993 IsaAccessTypeMem,
994 Width,
995 Count,
996 DestOffset
997 );
998 if (EFI_ERROR (Status)) {
999 return Status;
1000 }
1001
1002 Status = IsaIoVerifyAccess (
1003 IsaIoDevice,
1004 IsaAccessTypeMem,
1005 Width,
1006 Count,
1007 SrcOffset
1008 );
1009 if (EFI_ERROR (Status)) {
1010 return Status;
1011 }
1012
1013 Status = IsaIoDevice->PciIo->CopyMem (
1014 IsaIoDevice->PciIo,
1015 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
1016 EFI_PCI_IO_PASS_THROUGH_BAR,
1017 DestOffset,
1018 EFI_PCI_IO_PASS_THROUGH_BAR,
1019 SrcOffset,
1020 Count
1021 );
1022
1023 if (EFI_ERROR (Status)) {
1024 REPORT_STATUS_CODE (
1025 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1026 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
1027 );
1028 }
1029
1030 return Status;
1031 }
1032
1033 /**
1034 Maps a memory region for DMA, note this implementation
1035 only supports slave read/write operation to save code size.
1036
1037 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1038 @param Operation Indicates the type of DMA (slave or bus master), and if
1039 the DMA operation is going to read or write to system memory.
1040 @param ChannelNumber The slave channel number to use for this DMA operation.
1041 If Operation and ChannelAttributes shows that this device
1042 performs bus mastering DMA, then this field is ignored.
1043 The legal range for this field is 0..7.
1044 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
1045 @param HostAddress The system memory address to map to the device.
1046 @param NumberOfBytes On input the number of bytes to map. On output the number
1047 of bytes that were mapped.
1048 @param DeviceAddress The resulting map address for the bus master device to use
1049 to access the hosts HostAddress.
1050 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
1051
1052 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
1053 @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.
1054 @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.
1055 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
1056 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
1057 **/
1058 EFI_STATUS
1059 IsaIoMapOnlySupportSlaveReadWrite (
1060 IN EFI_ISA_IO_PROTOCOL *This,
1061 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation,
1062 IN UINT8 ChannelNumber OPTIONAL,
1063 IN UINT32 ChannelAttributes,
1064 IN VOID *HostAddress,
1065 IN OUT UINTN *NumberOfBytes,
1066 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
1067 OUT VOID **Mapping
1068 )
1069 {
1070 EFI_STATUS Status;
1071 EFI_PHYSICAL_ADDRESS PhysicalAddress;
1072 ISA_MAP_INFO *IsaMapInfo;
1073 UINT8 DmaMode;
1074 UINTN MaxNumberOfBytes;
1075 UINT32 BaseAddress;
1076 UINT16 Count;
1077 UINT8 DmaMask;
1078 UINT8 DmaClear;
1079 UINT8 DmaChannelMode;
1080
1081 if ((NULL == This) ||
1082 (NULL == HostAddress) ||
1083 (NULL == NumberOfBytes) ||
1084 (NULL == DeviceAddress) ||
1085 (NULL == Mapping)
1086 ) {
1087 return EFI_INVALID_PARAMETER;
1088 }
1089
1090 //
1091 // Initialize the return values to their defaults
1092 //
1093 *Mapping = NULL;
1094
1095 //
1096 // Make sure the Operation parameter is valid.
1097 // Light IsaIo only supports two operations.
1098 //
1099 if (!(Operation == EfiIsaIoOperationSlaveRead ||
1100 Operation == EfiIsaIoOperationSlaveWrite)) {
1101 return EFI_INVALID_PARAMETER;
1102 }
1103
1104 if (ChannelNumber >= 4) {
1105 //
1106 // The Light IsaIo doesn't support channelNumber larger than 4.
1107 //
1108 return EFI_INVALID_PARAMETER;
1109 }
1110
1111 //
1112 // Map the HostAddress to a DeviceAddress.
1113 //
1114 PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
1115 if ((PhysicalAddress + *NumberOfBytes) > BASE_16MB) {
1116 //
1117 // Common Buffer operations can not be remapped. If the common buffer
1118 // is above 16MB, then it is not possible to generate a mapping, so return
1119 // an error.
1120 //
1121 if (Operation == EfiIsaIoOperationBusMasterCommonBuffer) {
1122 return EFI_UNSUPPORTED;
1123 }
1124 //
1125 // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
1126 // is called later.
1127 //
1128 IsaMapInfo = AllocatePool (sizeof (ISA_MAP_INFO));
1129 if (IsaMapInfo == NULL) {
1130 *NumberOfBytes = 0;
1131 return EFI_OUT_OF_RESOURCES;
1132 }
1133 //
1134 // Return a pointer to the MAP_INFO structure in Mapping
1135 //
1136 *Mapping = IsaMapInfo;
1137
1138 //
1139 // Initialize the MAP_INFO structure
1140 //
1141 IsaMapInfo->Operation = Operation;
1142 IsaMapInfo->NumberOfBytes = *NumberOfBytes;
1143 IsaMapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (*NumberOfBytes);
1144 IsaMapInfo->HostAddress = PhysicalAddress;
1145 IsaMapInfo->MappedHostAddress = BASE_16MB - 1;
1146
1147 //
1148 // Allocate a buffer below 16MB to map the transfer to.
1149 //
1150 Status = gBS->AllocatePages (
1151 AllocateMaxAddress,
1152 EfiBootServicesData,
1153 IsaMapInfo->NumberOfPages,
1154 &IsaMapInfo->MappedHostAddress
1155 );
1156 if (EFI_ERROR (Status)) {
1157 FreePool (IsaMapInfo);
1158 *NumberOfBytes = 0;
1159 *Mapping = NULL;
1160 return Status;
1161 }
1162 //
1163 // If this is a read operation from the DMA agents's point of view,
1164 // then copy the contents of the real buffer into the mapped buffer
1165 // so the DMA agent can read the contents of the real buffer.
1166 //
1167 if (Operation == EfiIsaIoOperationSlaveRead) {
1168 CopyMem (
1169 (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,
1170 (VOID *) (UINTN) IsaMapInfo->HostAddress,
1171 IsaMapInfo->NumberOfBytes
1172 );
1173 }
1174 //
1175 // The DeviceAddress is the address of the maped buffer below 16 MB
1176 //
1177 *DeviceAddress = IsaMapInfo->MappedHostAddress;
1178 } else {
1179 //
1180 // The transfer is below 16 MB, so the DeviceAddress is simply the
1181 // HostAddress
1182 //
1183 *DeviceAddress = PhysicalAddress;
1184 }
1185
1186 //
1187 // Figure out what to program into the DMA Channel Mode Register
1188 //
1189 DmaMode = (UINT8) (B_8237_DMA_CHMODE_INCREMENT | (ChannelNumber & 0x03));
1190 if (Operation == EfiIsaIoOperationSlaveRead) {
1191 DmaMode |= V_8237_DMA_CHMODE_MEM2IO;
1192 } else {
1193 DmaMode |= V_8237_DMA_CHMODE_IO2MEM;
1194 }
1195 //
1196 // We only support EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE in simplified IsaIo
1197 //
1198 DmaMode |= V_8237_DMA_CHMODE_SINGLE;
1199
1200 //
1201 // A Slave DMA transfer can not cross a 64K boundary.
1202 // Compute *NumberOfBytes based on this restriction.
1203 //
1204 MaxNumberOfBytes = 0x10000 - ((UINT32) (*DeviceAddress) & 0xffff);
1205 if (*NumberOfBytes > MaxNumberOfBytes) {
1206 *NumberOfBytes = MaxNumberOfBytes;
1207 }
1208 //
1209 // Compute the values to program into the BaseAddress and Count registers
1210 // of the Slave DMA controller
1211 //
1212 BaseAddress = (UINT32) (*DeviceAddress);
1213 Count = (UINT16) (*NumberOfBytes - 1);
1214 //
1215 // Program the DMA Write Single Mask Register for ChannelNumber
1216 // Clear the DMA Byte Pointer Register
1217 //
1218 DmaMask = R_8237_DMA_WRSMSK_CH0_3;
1219 DmaClear = R_8237_DMA_CBPR_CH0_3;
1220 DmaChannelMode = R_8237_DMA_CHMODE_CH0_3;
1221
1222 Status = WritePort (
1223 This,
1224 DmaMask,
1225 (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
1226 );
1227 if (EFI_ERROR (Status)) {
1228 return Status;
1229 }
1230
1231 Status = WritePort (
1232 This,
1233 DmaClear,
1234 (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
1235 );
1236 if (EFI_ERROR (Status)) {
1237 return Status;
1238 }
1239
1240 Status = WritePort (This, DmaChannelMode, DmaMode);
1241 if (EFI_ERROR (Status)) {
1242 return Status;
1243 }
1244
1245 Status = WriteDmaPort (
1246 This,
1247 mDmaRegisters[ChannelNumber].Address,
1248 mDmaRegisters[ChannelNumber].Page,
1249 mDmaRegisters[ChannelNumber].Count,
1250 BaseAddress,
1251 Count
1252 );
1253 if (EFI_ERROR (Status)) {
1254 return Status;
1255 }
1256
1257 Status = WritePort (
1258 This,
1259 DmaMask,
1260 (UINT8) (ChannelNumber & 0x03)
1261 );
1262 if (EFI_ERROR (Status)) {
1263 return Status;
1264 }
1265
1266 return EFI_SUCCESS;
1267 }
1268
1269 /**
1270 Maps a memory region for DMA. This implementation implement the
1271 the full mapping support.
1272
1273 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1274 @param Operation Indicates the type of DMA (slave or bus master), and if
1275 the DMA operation is going to read or write to system memory.
1276 @param ChannelNumber The slave channel number to use for this DMA operation.
1277 If Operation and ChannelAttributes shows that this device
1278 performs bus mastering DMA, then this field is ignored.
1279 The legal range for this field is 0..7.
1280 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
1281 @param HostAddress The system memory address to map to the device.
1282 @param NumberOfBytes On input the number of bytes to map. On output the number
1283 of bytes that were mapped.
1284 @param DeviceAddress The resulting map address for the bus master device to use
1285 to access the hosts HostAddress.
1286 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
1287
1288 @retval EFI_SUCCESS - The range was mapped for the returned NumberOfBytes.
1289 @retval EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined.
1290 @retval EFI_UNSUPPORTED - The HostAddress can not be mapped as a common buffer.
1291 @retval EFI_DEVICE_ERROR - The system hardware could not map the requested address.
1292 @retval EFI_OUT_OF_RESOURCES - The memory pages could not be allocated.
1293 **/
1294 EFI_STATUS
1295 IsaIoMapFullSupport (
1296 IN EFI_ISA_IO_PROTOCOL *This,
1297 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation,
1298 IN UINT8 ChannelNumber OPTIONAL,
1299 IN UINT32 ChannelAttributes,
1300 IN VOID *HostAddress,
1301 IN OUT UINTN *NumberOfBytes,
1302 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
1303 OUT VOID **Mapping
1304 )
1305 {
1306 EFI_STATUS Status;
1307 BOOLEAN Master;
1308 BOOLEAN Read;
1309 EFI_PHYSICAL_ADDRESS PhysicalAddress;
1310 ISA_MAP_INFO *IsaMapInfo;
1311 UINT8 DmaMode;
1312 UINTN MaxNumberOfBytes;
1313 UINT32 BaseAddress;
1314 UINT16 Count;
1315 UINT8 DmaMask;
1316 UINT8 DmaClear;
1317 UINT8 DmaChannelMode;
1318
1319 if ((NULL == This) ||
1320 (NULL == HostAddress) ||
1321 (NULL == NumberOfBytes) ||
1322 (NULL == DeviceAddress) ||
1323 (NULL == Mapping)
1324 ) {
1325 return EFI_INVALID_PARAMETER;
1326 }
1327
1328 //
1329 // Initialize the return values to their defaults
1330 //
1331 *Mapping = NULL;
1332
1333 //
1334 // Make sure the Operation parameter is valid
1335 //
1336 if ((UINT32)Operation >= EfiIsaIoOperationMaximum) {
1337 return EFI_INVALID_PARAMETER;
1338 }
1339
1340 if (ChannelNumber >= 8) {
1341 return EFI_INVALID_PARAMETER;
1342 }
1343
1344 //
1345 // See if this is a Slave DMA Operation
1346 //
1347 Master = TRUE;
1348 Read = FALSE;
1349 if (Operation == EfiIsaIoOperationSlaveRead) {
1350 Operation = EfiIsaIoOperationBusMasterRead;
1351 Master = FALSE;
1352 Read = TRUE;
1353 }
1354
1355 if (Operation == EfiIsaIoOperationSlaveWrite) {
1356 Operation = EfiIsaIoOperationBusMasterWrite;
1357 Master = FALSE;
1358 Read = FALSE;
1359 }
1360
1361 if (!Master) {
1362 //
1363 // Make sure that ChannelNumber is a valid channel number
1364 // Channel 4 is used to cascade, so it is illegal.
1365 //
1366 if (ChannelNumber == 4 || ChannelNumber > 7) {
1367 return EFI_INVALID_PARAMETER;
1368 }
1369 //
1370 // This implementation only support COMPATIBLE DMA Transfers
1371 //
1372 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE) == 0) {
1373 return EFI_INVALID_PARAMETER;
1374 }
1375
1376 if ((ChannelAttributes &
1377 (EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A |
1378 EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B |
1379 EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C)) != 0) {
1380 return EFI_INVALID_PARAMETER;
1381 }
1382
1383 if (ChannelNumber < 4) {
1384 //
1385 // If this is Channel 0..3, then the width must be 8 bit
1386 //
1387 if (((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8) == 0) ||
1388 ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16) != 0)
1389 ) {
1390 return EFI_INVALID_PARAMETER;
1391 }
1392 } else {
1393 //
1394 // If this is Channel 4..7, then the width must be 16 bit
1395 //
1396 if (((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8) != 0) ||
1397 ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16) == 0)) {
1398 return EFI_INVALID_PARAMETER;
1399 }
1400 }
1401 //
1402 // Either Demand Mode or Single Mode must be selected, but not both
1403 //
1404 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) != 0) {
1405 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) != 0) {
1406 return EFI_INVALID_PARAMETER;
1407 }
1408 } else {
1409 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) == 0) {
1410 return EFI_INVALID_PARAMETER;
1411 }
1412 }
1413 }
1414 //
1415 // Map the HostAddress to a DeviceAddress.
1416 //
1417 PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
1418 if ((PhysicalAddress +*NumberOfBytes) > BASE_16MB) {
1419 //
1420 // Common Buffer operations can not be remapped. If the common buffer
1421 // is above 16MB, then it is not possible to generate a mapping, so return
1422 // an error.
1423 //
1424 if (Operation == EfiIsaIoOperationBusMasterCommonBuffer) {
1425 return EFI_UNSUPPORTED;
1426 }
1427 //
1428 // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
1429 // is called later.
1430 //
1431 IsaMapInfo = AllocatePool (sizeof (ISA_MAP_INFO));
1432 if (IsaMapInfo == NULL) {
1433 *NumberOfBytes = 0;
1434 return EFI_OUT_OF_RESOURCES;
1435 }
1436 //
1437 // Return a pointer to the MAP_INFO structure in Mapping
1438 //
1439 *Mapping = IsaMapInfo;
1440
1441 //
1442 // Initialize the MAP_INFO structure
1443 //
1444 IsaMapInfo->Operation = Operation;
1445 IsaMapInfo->NumberOfBytes = *NumberOfBytes;
1446 IsaMapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (*NumberOfBytes);
1447 IsaMapInfo->HostAddress = PhysicalAddress;
1448 IsaMapInfo->MappedHostAddress = BASE_16MB - 1;
1449
1450 //
1451 // Allocate a buffer below 16MB to map the transfer to.
1452 //
1453 Status = gBS->AllocatePages (
1454 AllocateMaxAddress,
1455 EfiBootServicesData,
1456 IsaMapInfo->NumberOfPages,
1457 &IsaMapInfo->MappedHostAddress
1458 );
1459 if (EFI_ERROR (Status)) {
1460 FreePool (IsaMapInfo);
1461 *NumberOfBytes = 0;
1462 *Mapping = NULL;
1463 return Status;
1464 }
1465 //
1466 // If this is a read operation from the DMA agents's point of view,
1467 // then copy the contents of the real buffer into the mapped buffer
1468 // so the DMA agent can read the contents of the real buffer.
1469 //
1470 if (Operation == EfiIsaIoOperationBusMasterRead) {
1471 CopyMem (
1472 (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,
1473 (VOID *) (UINTN) IsaMapInfo->HostAddress,
1474 IsaMapInfo->NumberOfBytes
1475 );
1476 }
1477 //
1478 // The DeviceAddress is the address of the maped buffer below 16 MB
1479 //
1480 *DeviceAddress = IsaMapInfo->MappedHostAddress;
1481 } else {
1482 //
1483 // The transfer is below 16 MB, so the DeviceAddress is simply the
1484 // HostAddress
1485 //
1486 *DeviceAddress = PhysicalAddress;
1487 }
1488 //
1489 // If this is a Bus Master operation then return
1490 //
1491 if (Master) {
1492 return EFI_SUCCESS;
1493 }
1494 //
1495 // Figure out what to program into the DMA Channel Mode Register
1496 //
1497 DmaMode = (UINT8) (B_8237_DMA_CHMODE_INCREMENT | (ChannelNumber & 0x03));
1498 if (Read) {
1499 DmaMode |= V_8237_DMA_CHMODE_MEM2IO;
1500 } else {
1501 DmaMode |= V_8237_DMA_CHMODE_IO2MEM;
1502 }
1503
1504 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_AUTO_INITIALIZE) != 0) {
1505 DmaMode |= B_8237_DMA_CHMODE_AE;
1506 }
1507
1508 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) != 0) {
1509 DmaMode |= V_8237_DMA_CHMODE_DEMAND;
1510 }
1511
1512 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) != 0) {
1513 DmaMode |= V_8237_DMA_CHMODE_SINGLE;
1514 }
1515 //
1516 // A Slave DMA transfer can not cross a 64K boundary.
1517 // Compute *NumberOfBytes based on this restriction.
1518 //
1519 MaxNumberOfBytes = 0x10000 - ((UINT32) (*DeviceAddress) & 0xffff);
1520 if (*NumberOfBytes > MaxNumberOfBytes) {
1521 *NumberOfBytes = MaxNumberOfBytes;
1522 }
1523 //
1524 // Compute the values to program into the BaseAddress and Count registers
1525 // of the Slave DMA controller
1526 //
1527 if (ChannelNumber < 4) {
1528 BaseAddress = (UINT32) (*DeviceAddress);
1529 Count = (UINT16) (*NumberOfBytes - 1);
1530 } else {
1531 BaseAddress = (UINT32) (((UINT32) (*DeviceAddress) & 0xff0000) | (((UINT32) (*DeviceAddress) & 0xffff) >> 1));
1532 Count = (UINT16) ((*NumberOfBytes - 1) >> 1);
1533 }
1534 //
1535 // Program the DMA Write Single Mask Register for ChannelNumber
1536 // Clear the DMA Byte Pointer Register
1537 //
1538 if (ChannelNumber < 4) {
1539 DmaMask = R_8237_DMA_WRSMSK_CH0_3;
1540 DmaClear = R_8237_DMA_CBPR_CH0_3;
1541 DmaChannelMode = R_8237_DMA_CHMODE_CH0_3;
1542 } else {
1543 DmaMask = R_8237_DMA_WRSMSK_CH4_7;
1544 DmaClear = R_8237_DMA_CBPR_CH4_7;
1545 DmaChannelMode = R_8237_DMA_CHMODE_CH4_7;
1546 }
1547
1548 Status = WritePort (
1549 This,
1550 DmaMask,
1551 (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
1552 );
1553 if (EFI_ERROR (Status)) {
1554 return Status;
1555 }
1556
1557 Status = WritePort (
1558 This,
1559 DmaClear,
1560 (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
1561 );
1562 if (EFI_ERROR (Status)) {
1563 return Status;
1564 }
1565
1566 Status = WritePort (This, DmaChannelMode, DmaMode);
1567 if (EFI_ERROR (Status)) {
1568 return Status;
1569 }
1570
1571 Status = WriteDmaPort (
1572 This,
1573 mDmaRegisters[ChannelNumber].Address,
1574 mDmaRegisters[ChannelNumber].Page,
1575 mDmaRegisters[ChannelNumber].Count,
1576 BaseAddress,
1577 Count
1578 );
1579 if (EFI_ERROR (Status)) {
1580 return Status;
1581 }
1582
1583 Status = WritePort (
1584 This,
1585 DmaMask,
1586 (UINT8) (ChannelNumber & 0x03)
1587 );
1588 if (EFI_ERROR (Status)) {
1589 return Status;
1590 }
1591
1592 return EFI_SUCCESS;
1593 }
1594
1595 /**
1596 Maps a memory region for DMA
1597
1598 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1599 @param Operation Indicates the type of DMA (slave or bus master), and if
1600 the DMA operation is going to read or write to system memory.
1601 @param ChannelNumber The slave channel number to use for this DMA operation.
1602 If Operation and ChannelAttributes shows that this device
1603 performs bus mastering DMA, then this field is ignored.
1604 The legal range for this field is 0..7.
1605 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
1606 @param HostAddress The system memory address to map to the device.
1607 @param NumberOfBytes On input the number of bytes to map. On output the number
1608 of bytes that were mapped.
1609 @param DeviceAddress The resulting map address for the bus master device to use
1610 to access the hosts HostAddress.
1611 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
1612
1613 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
1614 @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.
1615 @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.
1616 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
1617 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
1618 **/
1619 EFI_STATUS
1620 EFIAPI
1621 IsaIoMap (
1622 IN EFI_ISA_IO_PROTOCOL *This,
1623 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation,
1624 IN UINT8 ChannelNumber OPTIONAL,
1625 IN UINT32 ChannelAttributes,
1626 IN VOID *HostAddress,
1627 IN OUT UINTN *NumberOfBytes,
1628 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
1629 OUT VOID **Mapping
1630 )
1631 {
1632 //
1633 // Check if DMA is supported.
1634 //
1635 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) {
1636 return EFI_UNSUPPORTED;
1637 }
1638 //
1639 // Set Feature Flag PcdIsaBusSupportBusMaster to FALSE to disable support for
1640 // ISA Bus Master.
1641 //
1642 // So we just return EFI_UNSUPPORTED for these functions.
1643 //
1644 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0) {
1645 return IsaIoMapOnlySupportSlaveReadWrite (
1646 This,
1647 Operation,
1648 ChannelNumber,
1649 ChannelAttributes,
1650 HostAddress,
1651 NumberOfBytes,
1652 DeviceAddress,
1653 Mapping
1654 );
1655
1656 } else {
1657 return IsaIoMapFullSupport (
1658 This,
1659 Operation,
1660 ChannelNumber,
1661 ChannelAttributes,
1662 HostAddress,
1663 NumberOfBytes,
1664 DeviceAddress,
1665 Mapping
1666 );
1667 }
1668 }
1669
1670 /**
1671 Allocates pages that are suitable for an EfiIsaIoOperationBusMasterCommonBuffer mapping.
1672
1673 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1674 @param[in] Type The type allocation to perform.
1675 @param[in] MemoryType The type of memory to allocate.
1676 @param[in] Pages The number of pages to allocate.
1677 @param[out] HostAddress A pointer to store the base address of the allocated range.
1678 @param[in] Attributes The requested bit mask of attributes for the allocated range.
1679
1680 @retval EFI_SUCCESS The requested memory pages were allocated.
1681 @retval EFI_INVALID_PARAMETER Type is invalid or MemoryType is invalid or HostAddress is NULL
1682 @retval EFI_UNSUPPORTED Attributes is unsupported or the memory range specified
1683 by HostAddress, Pages, and Type is not available for common buffer use.
1684 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
1685 **/
1686 EFI_STATUS
1687 EFIAPI
1688 IsaIoAllocateBuffer (
1689 IN EFI_ISA_IO_PROTOCOL *This,
1690 IN EFI_ALLOCATE_TYPE Type,
1691 IN EFI_MEMORY_TYPE MemoryType,
1692 IN UINTN Pages,
1693 OUT VOID **HostAddress,
1694 IN UINT64 Attributes
1695 )
1696 {
1697 EFI_STATUS Status;
1698 EFI_PHYSICAL_ADDRESS PhysicalAddress;
1699
1700 //
1701 // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
1702 // ISA Bus Master.
1703 // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
1704 //
1705 if (((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) ||
1706 ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0)) {
1707 return EFI_UNSUPPORTED;
1708 }
1709
1710 if (HostAddress == NULL) {
1711 return EFI_INVALID_PARAMETER;
1712 }
1713
1714 if ((UINT32)Type >= MaxAllocateType) {
1715 return EFI_INVALID_PARAMETER;
1716 }
1717 //
1718 // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
1719 //
1720 if (MemoryType != EfiBootServicesData && MemoryType != EfiRuntimeServicesData) {
1721 return EFI_INVALID_PARAMETER;
1722 }
1723
1724 if ((Attributes & ~(EFI_ISA_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_ISA_IO_ATTRIBUTE_MEMORY_CACHED)) != 0) {
1725 return EFI_UNSUPPORTED;
1726 }
1727
1728 PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (BASE_16MB - 1);
1729 if (Type == AllocateAddress) {
1730 if ((UINTN) (*HostAddress) >= BASE_16MB) {
1731 return EFI_UNSUPPORTED;
1732 } else {
1733 PhysicalAddress = (UINTN) (*HostAddress);
1734 }
1735 }
1736
1737 if (Type == AllocateAnyPages) {
1738 Type = AllocateMaxAddress;
1739 }
1740
1741 Status = gBS->AllocatePages (Type, MemoryType, Pages, &PhysicalAddress);
1742 if (EFI_ERROR (Status)) {
1743 REPORT_STATUS_CODE (
1744 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1745 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
1746 );
1747 return Status;
1748 }
1749
1750 *HostAddress = (VOID *) (UINTN) PhysicalAddress;
1751 return Status;
1752 }
1753
1754 /**
1755 Frees memory that was allocated with EFI_ISA_IO.AllocateBuffer().
1756
1757 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
1758 @param[in] Pages The number of pages to free.
1759 @param[in] HostAddress The base address of the allocated range.
1760
1761 @retval EFI_SUCCESS The requested memory pages were freed.
1762 @retval EFI_INVALID_PARAMETER The memory was not allocated with EFI_ISA_IO.AllocateBufer().
1763 **/
1764 EFI_STATUS
1765 EFIAPI
1766 IsaIoFreeBuffer (
1767 IN EFI_ISA_IO_PROTOCOL *This,
1768 IN UINTN Pages,
1769 IN VOID *HostAddress
1770 )
1771 {
1772 EFI_STATUS Status;
1773
1774 //
1775 // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
1776 // ISA Bus Master.
1777 // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
1778 //
1779 if (((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) ||
1780 ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0)) {
1781 return EFI_UNSUPPORTED;
1782 }
1783
1784 Status = gBS->FreePages (
1785 (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress,
1786 Pages
1787 );
1788 if (EFI_ERROR (Status)) {
1789 REPORT_STATUS_CODE (
1790 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1791 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
1792 );
1793 }
1794
1795 return Status;
1796 }
1797