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