1 /** @file 2 The implementation for EFI_ISA_IO_PROTOCOL. 3 4 Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 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 1804