]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
MdeModulePkg/AtaAtapiPassThru: Ensure GHC.AE bit is always set in Ahci
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AtaAtapiPassThru / AhciMode.c
index f64a3407e4687d6902656d0716e748c10943006e..4d01c1dd7fca2c70d97250e9bace7840135e4d09 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   The file for AHCI mode of ATA host controller.\r
 \r
-  Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>\r
   (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
@@ -371,6 +371,7 @@ AhciClearPortStatus (
   in the Status Register, the Error Register's value is also be dumped.\r
 \r
   @param  PciIo            The PCI IO protocol instance.\r
+  @param  AhciRegisters    The pointer to the EFI_AHCI_REGISTERS.\r
   @param  Port             The number of port.\r
   @param  AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
 \r
@@ -379,24 +380,42 @@ VOID
 EFIAPI\r
 AhciDumpPortStatus (\r
   IN     EFI_PCI_IO_PROTOCOL        *PciIo,\r
+  IN     EFI_AHCI_REGISTERS         *AhciRegisters,\r
   IN     UINT8                      Port,\r
   IN OUT EFI_ATA_STATUS_BLOCK       *AtaStatusBlock\r
   )\r
 {\r
-  UINT32               Offset;\r
+  UINT               Offset;\r
   UINT32               Data;\r
+  UINTN                FisBaseAddr;\r
+  EFI_STATUS           Status;\r
 \r
   ASSERT (PciIo != NULL);\r
 \r
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
-  Data   = AhciReadReg (PciIo, Offset);\r
-\r
   if (AtaStatusBlock != NULL) {\r
     ZeroMem (AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
 \r
-    AtaStatusBlock->AtaStatus  = (UINT8)Data;\r
-    if ((AtaStatusBlock->AtaStatus & BIT0) != 0) {\r
-      AtaStatusBlock->AtaError = (UINT8)(Data >> 8);\r
+    FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
+    Offset      = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
+\r
+    Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, NULL);\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // If D2H FIS is received, update StatusBlock with its content.\r
+      //\r
+      CopyMem (AtaStatusBlock, (UINT8 *)Offset, sizeof (EFI_ATA_STATUS_BLOCK));\r
+    } else {\r
+      //\r
+      // If D2H FIS is not received, only update Status & Error field through PxTFD\r
+      // as there is no other way to get the content of the Shadow Register Block.\r
+      //\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
+      Data   = AhciReadReg (PciIo, (UINT32)Offset);\r
+\r
+      AtaStatusBlock->AtaStatus  = (UINT8)Data;\r
+      if ((AtaStatusBlock->AtaStatus & BIT0) != 0) {\r
+        AtaStatusBlock->AtaError = (UINT8)(Data >> 8);\r
+      }\r
     }\r
   }\r
 }\r
@@ -427,13 +446,7 @@ AhciEnableFisReceive (
   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
   AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);\r
 \r
-  return AhciWaitMmioSet (\r
-           PciIo,\r
-           Offset,\r
-           EFI_AHCI_PORT_CMD_FR,\r
-           EFI_AHCI_PORT_CMD_FR,\r
-           Timeout\r
-           );\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
@@ -872,7 +885,7 @@ Exit:
     Map\r
     );\r
 \r
-  AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
+  AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
 \r
   return Status;\r
 }\r
@@ -1091,7 +1104,7 @@ Exit:
     }\r
   }\r
 \r
-  AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
+  AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
   return Status;\r
 }\r
 \r
@@ -1207,7 +1220,7 @@ Exit:
     Timeout\r
     );\r
 \r
-  AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
+  AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
 \r
   return Status;\r
 }\r
@@ -1438,17 +1451,13 @@ AhciReset (
 {\r
   UINT64                 Delay;\r
   UINT32                 Value;\r
-  UINT32                 Capability;\r
 \r
   //\r
-  // Collect AHCI controller information\r
-  //\r
-  Capability = AhciReadReg (PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
-  \r
-  //\r
-  // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set\r
+  // Make sure that GHC.AE bit is set before accessing any AHCI registers.\r
   //\r
-  if ((Capability & EFI_AHCI_CAP_SAM) == 0) {\r
+  Value = AhciReadReg(PciIo, EFI_AHCI_GHC_OFFSET);\r
+\r
+  if ((Value & EFI_AHCI_GHC_ENABLE) == 0) {\r
     AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
   }\r
 \r
@@ -1484,7 +1493,7 @@ AhciReset (
   @param  PciIo               The PCI IO protocol instance.\r
   @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
   @param  Port                The number of port.\r
-  @param  PortMultiplier      The timeout value of stop.\r
+  @param  PortMultiplier      The port multiplier port number.\r
   @param  AtaStatusBlock      A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
 \r
   @retval EFI_SUCCESS     Successfully get the return status of S.M.A.R.T command execution.\r
@@ -1582,7 +1591,7 @@ AhciAtaSmartReturnStatusCheck (
   @param  PciIo               The PCI IO protocol instance.\r
   @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
   @param  Port                The number of port.\r
-  @param  PortMultiplier      The timeout value of stop.\r
+  @param  PortMultiplier      The port multiplier port number.\r
   @param  IdentifyData        A pointer to data buffer which is used to contain IDENTIFY data.\r
   @param  AtaStatusBlock      A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
 \r
@@ -1698,7 +1707,7 @@ AhciAtaSmartSupport (
   @param  PciIo               The PCI IO protocol instance.\r
   @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
   @param  Port                The number of port.\r
-  @param  PortMultiplier      The timeout value of stop.\r
+  @param  PortMultiplier      The port multiplier port number.\r
   @param  Buffer              The data buffer to store IDENTIFY PACKET data.\r
 \r
   @retval EFI_DEVICE_ERROR    The cmd abort with error occurs.\r
@@ -1756,7 +1765,7 @@ AhciIdentify (
   @param  PciIo               The PCI IO protocol instance.\r
   @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
   @param  Port                The number of port.\r
-  @param  PortMultiplier      The timeout value of stop.\r
+  @param  PortMultiplier      The port multiplier port number.\r
   @param  Buffer              The data buffer to store IDENTIFY PACKET data.\r
 \r
   @retval EFI_DEVICE_ERROR    The cmd abort with error occurs.\r
@@ -1814,7 +1823,7 @@ AhciIdentifyPacket (
   @param  PciIo               The PCI IO protocol instance.\r
   @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
   @param  Port                The number of port.\r
-  @param  PortMultiplier      The timeout value of stop.\r
+  @param  PortMultiplier      The port multiplier port number.\r
   @param  Feature             The data to send Feature register.\r
   @param  FeatureSpecificData The specific data for SET FEATURE cmd.\r
 \r
@@ -2239,6 +2248,7 @@ AhciModeInitialization (
   EFI_ATA_COLLECTIVE_MODE          *SupportedModes;\r
   EFI_ATA_TRANSFER_MODE            TransferMode;\r
   UINT32                           PhyDetectDelay;\r
+  UINT32                           Value;\r
 \r
   if (Instance == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -2257,14 +2267,34 @@ AhciModeInitialization (
   // Collect AHCI controller information\r
   //\r
   Capability = AhciReadReg (PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
-  \r
+\r
   //\r
-  // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set\r
+  // Make sure that GHC.AE bit is set before accessing any AHCI registers.\r
   //\r
-  if ((Capability & EFI_AHCI_CAP_SAM) == 0) {\r
+  Value = AhciReadReg(PciIo, EFI_AHCI_GHC_OFFSET);\r
+\r
+  if ((Value & EFI_AHCI_GHC_ENABLE) == 0) {\r
     AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
   }\r
-  \r
+\r
+  //\r
+  // Enable 64-bit DMA support in the PCI layer if this controller\r
+  // supports it.\r
+  //\r
+  if ((Capability & EFI_AHCI_CAP_S64A) != 0) {\r
+    Status = PciIo->Attributes (\r
+                      PciIo,\r
+                      EfiPciIoAttributeOperationEnable,\r
+                      EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,\r
+                      NULL\r
+                      );\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_WARN,\r
+        "AhciModeInitialization: failed to enable 64-bit DMA on 64-bit capable controller (%r)\n",\r
+        Status));\r
+    }\r
+  }\r
+\r
   //\r
   // Get the number of command slots per port supported by this HBA.\r
   //\r
@@ -2344,16 +2374,6 @@ AhciModeInitialization (
       //\r
       Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
       AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);\r
-      Status = AhciWaitMmioSet (\r
-                 PciIo,\r
-                 Offset,\r
-                 EFI_AHCI_PORT_CMD_FR,\r
-                 EFI_AHCI_PORT_CMD_FR,\r
-                 EFI_AHCI_PORT_CMD_FR_CLEAR_TIMEOUT\r
-                 );\r
-      if (EFI_ERROR (Status)) {\r
-        continue;\r
-      }\r
 \r
       //\r
       // Wait no longer than 10 ms to wait the Phy to detect the presence of a device.\r
@@ -2513,7 +2533,7 @@ AhciModeInitialization (
       //\r
       // Found a ATA or ATAPI device, add it into the device list.\r
       //\r
-      CreateNewDeviceInfo (Instance, Port, 0, DeviceType, &Buffer);\r
+      CreateNewDeviceInfo (Instance, Port, 0xFFFF, DeviceType, &Buffer);\r
       if (DeviceType == EfiIdeHarddisk) {\r
         REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_PC_ENABLE));\r
       }\r