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