]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
MdeModulePkg AtaAtapiPassThru: Remove redundant functions
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AtaAtapiPassThru / AhciMode.c
index 841b6a0e60634ab11dc3634088b39f1ad02532fc..d7a8b296663e0ac20cf4b7eb4d5e9e873e8d791b 100644 (file)
@@ -294,41 +294,6 @@ AhciCheckMemSet (
   }\r
 }\r
 \r
-/**\r
-  Check if the device is still on port. It also checks if the AHCI controller\r
-  supports the address and data count will be transferred.\r
-\r
-  @param  PciIo            The PCI IO protocol instance.\r
-  @param  Port             The number of port.\r
-\r
-  @retval EFI_SUCCESS      The device is attached to port and the transfer data is\r
-                           supported by AHCI controller.\r
-  @retval EFI_UNSUPPORTED  The transfer address and count is not supported by AHCI\r
-                           controller.\r
-  @retval EFI_NOT_READY    The physical communication between AHCI controller and device\r
-                           is not ready.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AhciCheckDeviceStatus (\r
-  IN  EFI_PCI_IO_PROTOCOL    *PciIo,\r
-  IN  UINT8                  Port\r
-  )\r
-{\r
-  UINT32      Data;\r
-  UINT32      Offset;\r
-\r
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
-\r
-  Data   = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;\r
-\r
-  if (Data == EFI_AHCI_PORT_SSTS_DET_PCE) {\r
-    return EFI_SUCCESS;\r
-  }\r
-\r
-  return EFI_NOT_READY;\r
-}\r
 \r
 /**\r
 \r
@@ -820,7 +785,7 @@ AhciPioTransfer (
         Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
         PortTfd = AhciReadReg (PciIo, (UINT32) Offset);\r
         //\r
-        // PxTFD will be updated if there is a D2H or SetupFIS received. \r
+        // PxTFD will be updated if there is a D2H or SetupFIS received.\r
         //\r
         if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
           Status = EFI_DEVICE_ERROR;\r
@@ -1361,75 +1326,6 @@ AhciStartCommand (
   return EFI_SUCCESS;\r
 }\r
 \r
-/**\r
-  Do AHCI port reset.\r
-\r
-  @param  PciIo              The PCI IO protocol instance.\r
-  @param  Port               The number of port.\r
-  @param  Timeout            The timeout value of reset, uses 100ns as a unit.\r
-\r
-  @retval EFI_DEVICE_ERROR   The port reset unsuccessfully\r
-  @retval EFI_TIMEOUT        The reset operation is time out.\r
-  @retval EFI_SUCCESS        The port reset successfully.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AhciPortReset (\r
-  IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
-  IN  UINT8                     Port,\r
-  IN  UINT64                    Timeout\r
-  )\r
-{\r
-  EFI_STATUS      Status;\r
-  UINT32          Offset;\r
-\r
-  AhciClearPortStatus (PciIo, Port);\r
-\r
-  AhciStopCommand (PciIo, Port, Timeout);\r
-\r
-  AhciDisableFisReceive (PciIo, Port, Timeout);\r
-\r
-  AhciEnableFisReceive (PciIo, Port, Timeout);\r
-\r
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
-\r
-  AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_DET_INIT);\r
-\r
-  //\r
-  // wait 5 millisecond before de-assert DET\r
-  //\r
-  MicroSecondDelay (5000);\r
-\r
-  AhciAndReg (PciIo, Offset, (UINT32)EFI_AHCI_PORT_SCTL_MASK);\r
-\r
-  //\r
-  // wait 5 millisecond before de-assert DET\r
-  //\r
-  MicroSecondDelay (5000);\r
-\r
-  //\r
-  // Wait for communication to be re-established\r
-  //\r
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
-  Status = AhciWaitMmioSet (\r
-             PciIo,\r
-             Offset,\r
-             EFI_AHCI_PORT_SSTS_DET_MASK,\r
-             EFI_AHCI_PORT_SSTS_DET_PCE,\r
-             Timeout\r
-             );\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "Port %d COMRESET failed: %r\n", Port, Status));\r
-    return Status;\r
-  }\r
-\r
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
-  AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_ERR_CLEAR);\r
-\r
-  return EFI_SUCCESS;\r
-}\r
 \r
 /**\r
   Do AHCI HBA reset.\r
@@ -2010,7 +1906,7 @@ AhciCreateTransferDescriptor (
   //\r
   MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);\r
   Support64Bit         = (BOOLEAN) (((Capability & BIT31) != 0) ? TRUE : FALSE);\r
-  \r
+\r
   PortImplementBitMap  = AhciReadReg(PciIo, EFI_AHCI_PI_OFFSET);\r
   //\r
   // Get the highest bit of implemented ports which decides how many bytes are allocated for recived FIS.\r
@@ -2218,6 +2114,213 @@ Error6:
   return Status;\r
 }\r
 \r
+/**\r
+  Read logs from SATA device.\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  PortMultiplier      The multiplier of port.\r
+  @param  Buffer              The data buffer to store SATA logs.\r
+  @param  LogNumber           The address of the log.\r
+  @param  PageNumber          The page number of the log.\r
+\r
+  @retval EFI_INVALID_PARAMETER  PciIo, AhciRegisters or Buffer is NULL.\r
+  @retval others                 Return status of AhciPioTransfer().\r
+**/\r
+EFI_STATUS\r
+AhciReadLogExt (\r
+  IN EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN EFI_AHCI_REGISTERS        *AhciRegisters,\r
+  IN UINT8                     Port,\r
+  IN UINT8                     PortMultiplier,\r
+  IN OUT UINT8                 *Buffer,\r
+  IN UINT8                     LogNumber,\r
+  IN UINT8                     PageNumber\r
+  )\r
+{\r
+  EFI_ATA_COMMAND_BLOCK        AtaCommandBlock;\r
+  EFI_ATA_STATUS_BLOCK         AtaStatusBlock;\r
+\r
+  if (PciIo == NULL || AhciRegisters == NULL || Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ///\r
+  /// Read log from device\r
+  ///\r
+  ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+  ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
+  ZeroMem (Buffer, 512);\r
+\r
+  AtaCommandBlock.AtaCommand      = ATA_CMD_READ_LOG_EXT;\r
+  AtaCommandBlock.AtaSectorCount  = 1;\r
+  AtaCommandBlock.AtaSectorNumber = LogNumber;\r
+  AtaCommandBlock.AtaCylinderLow  = PageNumber;\r
+\r
+  return AhciPioTransfer (\r
+           PciIo,\r
+           AhciRegisters,\r
+           Port,\r
+           PortMultiplier,\r
+           NULL,\r
+           0,\r
+           TRUE,\r
+           &AtaCommandBlock,\r
+           &AtaStatusBlock,\r
+           Buffer,\r
+           512,\r
+           ATA_ATAPI_TIMEOUT,\r
+           NULL\r
+           );\r
+}\r
+\r
+/**\r
+  Enable DEVSLP of the disk if supported.\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  PortMultiplier      The multiplier of port.\r
+  @param  IdentifyData        A pointer to data buffer which is used to contain IDENTIFY data.\r
+\r
+  @retval EFI_SUCCESS         The DEVSLP is enabled per policy successfully.\r
+  @retval EFI_UNSUPPORTED     The DEVSLP isn't supported by the controller/device and policy requires to enable it.\r
+**/\r
+EFI_STATUS\r
+AhciEnableDevSlp (\r
+  IN EFI_PCI_IO_PROTOCOL           *PciIo,\r
+  IN EFI_AHCI_REGISTERS            *AhciRegisters,\r
+  IN UINT8                         Port,\r
+  IN UINT8                         PortMultiplier,\r
+  IN EFI_IDENTIFY_DATA             *IdentifyData\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  UINT32                   Offset;\r
+  UINT32                   Capability2;\r
+  UINT8                    LogData[512];\r
+  DEVSLP_TIMING_VARIABLES  DevSlpTiming;\r
+  UINT32                   PortCmd;\r
+  UINT32                   PortDevSlp;\r
+\r
+  if (mAtaAtapiPolicy->DeviceSleepEnable != 1) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Do not enable DevSlp if DevSlp is not supported.\r
+  //\r
+  Capability2 = AhciReadReg (PciIo, AHCI_CAPABILITY2_OFFSET);\r
+  DEBUG ((DEBUG_INFO, "AHCI CAPABILITY2 = %08x\n", Capability2));\r
+  if ((Capability2 & AHCI_CAP2_SDS) == 0) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Do not enable DevSlp if DevSlp is not present\r
+  // Do not enable DevSlp if Hot Plug or Mechanical Presence Switch is supported\r
+  //\r
+  Offset     = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH;\r
+  PortCmd    = AhciReadReg (PciIo, Offset + EFI_AHCI_PORT_CMD);\r
+  PortDevSlp = AhciReadReg (PciIo, Offset + AHCI_PORT_DEVSLP);\r
+  DEBUG ((DEBUG_INFO, "Port CMD/DEVSLP = %08x / %08x\n", PortCmd, PortDevSlp));\r
+  if (((PortDevSlp & AHCI_PORT_DEVSLP_DSP) == 0) ||\r
+      ((PortCmd & (EFI_AHCI_PORT_CMD_HPCP | EFI_AHCI_PORT_CMD_MPSP)) != 0)\r
+     ) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Do not enable DevSlp if the device doesn't support DevSlp\r
+  //\r
+  DEBUG ((DEBUG_INFO, "IDENTIFY DEVICE: [77] = %04x, [78] = %04x, [79] = %04x\n",\r
+          IdentifyData->AtaData.reserved_77,\r
+          IdentifyData->AtaData.serial_ata_features_supported, IdentifyData->AtaData.serial_ata_features_enabled));\r
+  if ((IdentifyData->AtaData.serial_ata_features_supported & BIT8) == 0) {\r
+    DEBUG ((DEBUG_INFO, "DevSlp feature is not supported for device at port [%d] PortMultiplier [%d]!\n",\r
+            Port, PortMultiplier));\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Enable DevSlp when it is not enabled.\r
+  //\r
+  if ((IdentifyData->AtaData.serial_ata_features_enabled & BIT8) != 0) {\r
+    Status = AhciDeviceSetFeature (\r
+      PciIo, AhciRegisters, Port, 0, ATA_SUB_CMD_ENABLE_SATA_FEATURE, 0x09, ATA_ATAPI_TIMEOUT\r
+    );\r
+    DEBUG ((DEBUG_INFO, "DevSlp set feature for device at port [%d] PortMultiplier [%d] - %r\n",\r
+            Port, PortMultiplier, Status));\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  Status = AhciReadLogExt(PciIo, AhciRegisters, Port, PortMultiplier, LogData, 0x30, 0x08);\r
+\r
+  //\r
+  // Clear PxCMD.ST and PxDEVSLP.ADSE before updating PxDEVSLP.DITO and PxDEVSLP.MDAT.\r
+  //\r
+  AhciWriteReg (PciIo, Offset + EFI_AHCI_PORT_CMD, PortCmd & ~EFI_AHCI_PORT_CMD_ST);\r
+  PortDevSlp &= ~AHCI_PORT_DEVSLP_ADSE;\r
+  AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
+\r
+  //\r
+  // Set PxDEVSLP.DETO and PxDEVSLP.MDAT to 0.\r
+  //\r
+  PortDevSlp &= ~AHCI_PORT_DEVSLP_DETO_MASK;\r
+  PortDevSlp &= ~AHCI_PORT_DEVSLP_MDAT_MASK;\r
+  AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
+  DEBUG ((DEBUG_INFO, "Read Log Ext at port [%d] PortMultiplier [%d] - %r\n", Port, PortMultiplier, Status));\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Assume DEVSLP TIMING VARIABLES is not supported if the Identify Device Data log (30h, 8) fails\r
+    //\r
+    ZeroMem (&DevSlpTiming, sizeof (DevSlpTiming));\r
+  } else {\r
+    CopyMem (&DevSlpTiming, &LogData[48], sizeof (DevSlpTiming));\r
+    DEBUG ((DEBUG_INFO, "DevSlpTiming: Supported(%d), Deto(%d), Madt(%d)\n",\r
+            DevSlpTiming.Supported, DevSlpTiming.Deto, DevSlpTiming.Madt));\r
+  }\r
+\r
+  //\r
+  // Use 20ms as default DETO when DEVSLP TIMING VARIABLES is not supported or the DETO is 0.\r
+  //\r
+  if ((DevSlpTiming.Supported == 0) || (DevSlpTiming.Deto == 0)) {\r
+    DevSlpTiming.Deto = 20;\r
+  }\r
+\r
+  //\r
+  // Use 10ms as default MADT when DEVSLP TIMING VARIABLES is not supported or the MADT is 0.\r
+  //\r
+  if ((DevSlpTiming.Supported == 0) || (DevSlpTiming.Madt == 0)) {\r
+    DevSlpTiming.Madt = 10;\r
+  }\r
+\r
+  PortDevSlp |= DevSlpTiming.Deto << 2;\r
+  PortDevSlp |= DevSlpTiming.Madt << 10;\r
+  AhciOrReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
+\r
+  if (mAtaAtapiPolicy->AggressiveDeviceSleepEnable == 1) {\r
+    if ((Capability2 & AHCI_CAP2_SADM) != 0) {\r
+      PortDevSlp &= ~AHCI_PORT_DEVSLP_DITO_MASK;\r
+      PortDevSlp |= (625 << 15);\r
+      AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
+\r
+      PortDevSlp |= AHCI_PORT_DEVSLP_ADSE;\r
+      AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
+    }\r
+  }\r
+\r
+\r
+  AhciWriteReg (PciIo, Offset + EFI_AHCI_PORT_CMD, PortCmd);\r
+\r
+  DEBUG ((DEBUG_INFO, "Enabled DevSlp feature at port [%d] PortMultiplier [%d], Port CMD/DEVSLP = %08x / %08x\n",\r
+          Port, PortMultiplier, PortCmd, PortDevSlp));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
 \r
 /**\r
   Spin-up disk if IDD was incomplete or PUIS feature is enabled\r
@@ -2689,6 +2792,13 @@ AhciModeInitialization (
       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
+        AhciEnableDevSlp (\r
+          PciIo,\r
+          AhciRegisters,\r
+          Port,\r
+          0,\r
+          &Buffer\r
+          );\r
       }\r
 \r
       //\r