]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c
MdeModulePkg/AtaAtapiPassThru: Revert patch to disable Bus Master
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AtaAtapiPassThru / IdeMode.c
index e5beea65a22d1489613eb4987db133b71d3a3998..6478f7be07ddd1260ce9d321dab19e4d798617dd 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Header file for AHCI mode of ATA host controller.\r
 \r
-  Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>\r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
   which accompanies this distribution.  The full text of the license may be found at\r
@@ -467,9 +467,18 @@ DRQClear2 (
   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
   @param Timeout          The time to complete the command, uses 100ns as a unit.\r
 \r
-  @retval EFI_SUCCESS          DRQ bit set within the time out.\r
-  @retval EFI_TIMEOUT          DRQ bit not set within the time out.\r
-  @retval EFI_ABORTED          DRQ bit not set caused by the command abort.\r
+  @retval EFI_SUCCESS           BSY bit cleared and DRQ bit set within the\r
+                                timeout.\r
+\r
+  @retval EFI_TIMEOUT           BSY bit not cleared within the timeout.\r
+\r
+  @retval EFI_ABORTED           Polling abandoned due to command abort.\r
+\r
+  @retval EFI_DEVICE_ERROR      Polling abandoned due to a non-abort error.\r
+\r
+  @retval EFI_NOT_READY         BSY bit cleared within timeout, and device\r
+                                reported "command complete" by clearing DRQ\r
+                                bit.\r
 \r
   @note  Read Status Register will clear interrupt status.\r
 \r
@@ -542,9 +551,19 @@ DRQReady (
   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
   @param Timeout          The time to complete the command, uses 100ns as a unit.\r
 \r
-  @retval EFI_SUCCESS           DRQ bit set within the time out.\r
-  @retval EFI_TIMEOUT           DRQ bit not set within the time out.\r
-  @retval EFI_ABORTED           DRQ bit not set caused by the command abort.\r
+  @retval EFI_SUCCESS           BSY bit cleared and DRQ bit set within the\r
+                                timeout.\r
+\r
+  @retval EFI_TIMEOUT           BSY bit not cleared within the timeout.\r
+\r
+  @retval EFI_ABORTED           Polling abandoned due to command abort.\r
+\r
+  @retval EFI_DEVICE_ERROR      Polling abandoned due to a non-abort error.\r
+\r
+  @retval EFI_NOT_READY         BSY bit cleared within timeout, and device\r
+                                reported "command complete" by clearing DRQ\r
+                                bit.\r
+\r
   @note  Read Alternate Status Register will not clear interrupt status.\r
 \r
 **/\r
@@ -1525,7 +1544,7 @@ AtaUdmaInOut (
   UINTN                         PrdTableSize;\r
   EFI_PHYSICAL_ADDRESS          PrdTableMapAddr;\r
   VOID                          *PrdTableMap;\r
-  EFI_ATA_DMA_PRD               *PrdBaseAddr;\r
+  EFI_PHYSICAL_ADDRESS          PrdTableBaseAddr;\r
   EFI_ATA_DMA_PRD               *TempPrdBaseAddr;\r
   UINTN                         PrdTableNum;\r
 \r
@@ -1543,12 +1562,17 @@ AtaUdmaInOut (
   EFI_PCI_IO_PROTOCOL           *PciIo;\r
   EFI_TPL                       OldTpl;\r
 \r
+  UINTN                         AlignmentMask;\r
+  UINTN                         RealPageCount;\r
+  EFI_PHYSICAL_ADDRESS          BaseAddr;\r
+  EFI_PHYSICAL_ADDRESS          BaseMapAddr;\r
 \r
   Status        = EFI_SUCCESS;\r
-  PrdBaseAddr   = NULL;\r
   PrdTableMap   = NULL;\r
   BufferMap     = NULL;\r
   PageCount     = 0;\r
+  RealPageCount = 0;\r
+  BaseAddr      = 0;\r
   PciIo         = Instance->PciIo;\r
 \r
   if ((PciIo == NULL) || (IdeRegisters == NULL) || (DataBuffer == NULL) || (AtaCommandBlock == NULL)) {\r
@@ -1606,40 +1630,56 @@ AtaUdmaInOut (
 \r
     //\r
     // Allocate buffer for PRD table initialization.\r
+    // Note Ide Bus Master spec said the descriptor table must be aligned on a 4 byte\r
+    // boundary and the table cannot cross a 64K boundary in memory.\r
+    //\r
+    PageCount     = EFI_SIZE_TO_PAGES (PrdTableSize);\r
+    RealPageCount = PageCount + EFI_SIZE_TO_PAGES (SIZE_64KB);\r
+\r
+    //\r
+    // Make sure that PageCount plus EFI_SIZE_TO_PAGES (SIZE_64KB) does not overflow.\r
     //\r
-    PageCount = EFI_SIZE_TO_PAGES (PrdTableSize);\r
+    ASSERT (RealPageCount > PageCount);\r
+\r
     Status    = PciIo->AllocateBuffer (\r
                          PciIo,\r
                          AllocateAnyPages,\r
                          EfiBootServicesData,\r
-                         PageCount,\r
-                         (VOID **)&PrdBaseAddr,\r
+                         RealPageCount,\r
+                         (VOID **)&BaseAddr,\r
                          0\r
                          );\r
     if (EFI_ERROR (Status)) {\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
 \r
-    ByteCount = EFI_PAGES_TO_SIZE (PageCount);\r
+    ByteCount = EFI_PAGES_TO_SIZE (RealPageCount);\r
     Status    = PciIo->Map (\r
                          PciIo,\r
                          EfiPciIoOperationBusMasterCommonBuffer,\r
-                         PrdBaseAddr,\r
+                         (VOID*)(UINTN)BaseAddr,\r
                          &ByteCount,\r
-                         &PrdTableMapAddr,\r
+                         &BaseMapAddr,\r
                          &PrdTableMap\r
                          );\r
-    if (EFI_ERROR (Status) || (ByteCount != EFI_PAGES_TO_SIZE (PageCount))) {\r
+    if (EFI_ERROR (Status) || (ByteCount != EFI_PAGES_TO_SIZE (RealPageCount))) {\r
       //\r
       // If the data length actually mapped is not equal to the requested amount,\r
       // it means the DMA operation may be broken into several discontinuous smaller chunks.\r
       // Can't handle this case.\r
       //\r
-      PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
+      PciIo->FreeBuffer (PciIo, RealPageCount, (VOID*)(UINTN)BaseAddr);\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
 \r
-    ZeroMem ((VOID *) ((UINTN) PrdBaseAddr), ByteCount);\r
+    ZeroMem ((VOID *) ((UINTN) BaseAddr), ByteCount);\r
+\r
+    //\r
+    // Calculate the 64K align address as PRD Table base address.\r
+    //\r
+    AlignmentMask    = SIZE_64KB - 1;\r
+    PrdTableBaseAddr = ((UINTN) BaseAddr + AlignmentMask) & ~AlignmentMask;\r
+    PrdTableMapAddr  = ((UINTN) BaseMapAddr + AlignmentMask) & ~AlignmentMask;\r
 \r
     //\r
     // Map the host address of DataBuffer to DMA master address.\r
@@ -1661,7 +1701,7 @@ AtaUdmaInOut (
                          );\r
     if (EFI_ERROR (Status) || (ByteCount != DataLength)) {\r
       PciIo->Unmap (PciIo, PrdTableMap);\r
-      PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
+      PciIo->FreeBuffer (PciIo, RealPageCount, (VOID*)(UINTN)BaseAddr);\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
 \r
@@ -1675,7 +1715,7 @@ AtaUdmaInOut (
     // Fill the PRD table with appropriate bus master address of data buffer and data length.\r
     //\r
     ByteRemaining   = ByteCount;\r
-    TempPrdBaseAddr = PrdBaseAddr;\r
+    TempPrdBaseAddr = (EFI_ATA_DMA_PRD*)(UINTN)PrdTableBaseAddr;\r
     while (ByteRemaining != 0) {\r
       if (ByteRemaining <= 0x10000) {\r
         TempPrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress);\r
@@ -1731,8 +1771,8 @@ AtaUdmaInOut (
     if (Task != NULL) {\r
       Task->Map            = BufferMap;\r
       Task->TableMap       = PrdTableMap;\r
-      Task->MapBaseAddress = PrdBaseAddr;\r
-      Task->PageCount      = PageCount;\r
+      Task->MapBaseAddress = (EFI_ATA_DMA_PRD*)(UINTN)BaseAddr;\r
+      Task->PageCount      = RealPageCount;\r
       Task->IsStart        = TRUE;\r
     }\r
 \r
@@ -1819,7 +1859,7 @@ Exit:
       PciIo->Unmap (PciIo, Task->Map);\r
     } else {\r
       PciIo->Unmap (PciIo, PrdTableMap);\r
-      PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
+      PciIo->FreeBuffer (PciIo, RealPageCount, (VOID*)(UINTN)BaseAddr);\r
       PciIo->Unmap (PciIo, BufferMap);\r
     }\r
 \r
@@ -1896,7 +1936,7 @@ AtaPacketReadWrite (
   IN     EFI_PCI_IO_PROTOCOL       *PciIo,\r
   IN     EFI_IDE_REGISTERS         *IdeRegisters,\r
   IN OUT VOID                      *Buffer,\r
-  IN     UINT64                    ByteCount,\r
+  IN OUT UINT32                    *ByteCount,\r
   IN     BOOLEAN                   Read,\r
   IN     UINT64                    Timeout\r
   )\r
@@ -1907,17 +1947,18 @@ AtaPacketReadWrite (
   EFI_STATUS  Status;\r
   UINT16      *PtrBuffer;\r
 \r
+  PtrBuffer         = Buffer;\r
+  RequiredWordCount = *ByteCount >> 1;\r
+\r
   //\r
   // No data transfer is premitted.\r
   //\r
-  if (ByteCount == 0) {\r
+  if (RequiredWordCount == 0) {\r
     return EFI_SUCCESS;\r
   }\r
 \r
-  PtrBuffer         = Buffer;\r
-  RequiredWordCount = (UINT32)RShiftU64(ByteCount, 1);\r
   //\r
-  // ActuralWordCount means the word count of data really transferred.\r
+  // ActualWordCount means the word count of data really transferred.\r
   //\r
   ActualWordCount = 0;\r
 \r
@@ -1928,7 +1969,15 @@ AtaPacketReadWrite (
     //\r
     Status = DRQReady2 (PciIo, IdeRegisters, Timeout);\r
     if (EFI_ERROR (Status)) {\r
-      return CheckStatusRegister (PciIo, IdeRegisters);\r
+      if (Status == EFI_NOT_READY) {\r
+        //\r
+        // Device provided less data than we intended to read, or wanted less\r
+        // data than we intended to write, but it may still be successful.\r
+        //\r
+        break;\r
+      } else {\r
+        return Status;\r
+      }\r
     }\r
 \r
     //\r
@@ -1994,6 +2043,7 @@ AtaPacketReadWrite (
     return EFI_DEVICE_ERROR;\r
   }\r
 \r
+  *ByteCount = ActualWordCount << 1;\r
   return Status;\r
 }\r
 \r
@@ -2092,7 +2142,7 @@ AtaPacketCommandExecute (
                PciIo,\r
                IdeRegisters,\r
                Packet->InDataBuffer,\r
-               Packet->InTransferLength,\r
+               &Packet->InTransferLength,\r
                TRUE,\r
                Packet->Timeout\r
                );\r
@@ -2101,7 +2151,7 @@ AtaPacketCommandExecute (
                PciIo,\r
                IdeRegisters,\r
                Packet->OutDataBuffer,\r
-               Packet->OutTransferLength,\r
+               &Packet->OutTransferLength,\r
                FALSE,\r
                Packet->Timeout\r
                );\r
@@ -2592,6 +2642,11 @@ DetectAndConfigIdeDevice (
   PciIo        = Instance->PciIo;\r
 \r
   for (IdeDevice = 0; IdeDevice < EfiIdeMaxDevice; IdeDevice++) {\r
+    //\r
+    // Select Master or Slave device to get the return signature for ATA DEVICE DIAGNOSTIC cmd.\r
+    //\r
+    IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)((IdeDevice << 4) | 0xe0));\r
+\r
     //\r
     // Send ATA Device Execut Diagnostic command.\r
     // This command should work no matter DRDY is ready or not\r