]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
MdeModulePkg/AtaAtapiPassThru: don't write read-only AHCI MMIO register
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AtaAtapiPassThru / AhciMode.c
index 7fc7a2812676bcace176849a87558d2c20e41a0b..186d40c062ac7e8c3745783ce1fa5b870b8afdf1 100644 (file)
@@ -704,6 +704,8 @@ AhciPioTransfer (
   UINT32                        PortTfd;\r
   UINT32                        PrdCount;\r
   BOOLEAN                       InfiniteWait;\r
+  BOOLEAN                       PioFisReceived;\r
+  BOOLEAN                       D2hFisReceived;\r
 \r
   if (Timeout == 0) {\r
     InfiniteWait = TRUE;\r
@@ -780,15 +782,31 @@ AhciPioTransfer (
     Status = EFI_TIMEOUT;\r
     Delay  = DivU64x32 (Timeout, 1000) + 1;\r
     do {\r
+      PioFisReceived = FALSE;\r
+      D2hFisReceived = FALSE;\r
       Offset = FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET;\r
-\r
       Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_PIO_SETUP, NULL);\r
       if (!EFI_ERROR (Status)) {\r
+        PioFisReceived = TRUE;\r
+      }\r
+      //\r
+      // According to SATA 2.6 spec section 11.7, D2h FIS means an error encountered.\r
+      // But Qemu and Marvel 9230 sata controller may just receive a D2h FIS from device\r
+      // after the transaction is finished successfully.\r
+      // To get better device compatibilities, we further check if the PxTFD's ERR bit is set.\r
+      // By this way, we can know if there is a real error happened.\r
+      //\r
+      Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
+      Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, NULL);\r
+      if (!EFI_ERROR (Status)) {\r
+        D2hFisReceived = TRUE;\r
+      }\r
+\r
+      if (PioFisReceived || D2hFisReceived) {\r
         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
-        // For PIO IN transfer, D2H means a device error. Therefore we only need to check the TFD after receiving a SetupFIS.\r
         //\r
         if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
           Status = EFI_DEVICE_ERROR;\r
@@ -797,23 +815,20 @@ AhciPioTransfer (
 \r
         PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));\r
         if (PrdCount == DataCount) {\r
+          Status = EFI_SUCCESS;\r
           break;\r
         }\r
       }\r
 \r
-      Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
-      Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, NULL);\r
-      if (!EFI_ERROR (Status)) {\r
-        Status = EFI_DEVICE_ERROR;\r
-        break;\r
-      }\r
-\r
       //\r
       // Stall for 100 microseconds.\r
       //\r
       MicroSecondDelay(100);\r
 \r
       Delay--;\r
+      if (Delay == 0) {\r
+        Status = EFI_TIMEOUT;\r
+      }\r
     } while (InfiniteWait || (Delay > 0));\r
   } else {\r
     //\r
@@ -1425,8 +1440,19 @@ AhciReset (
 {\r
   UINT64                 Delay;\r
   UINT32                 Value;\r
+  UINT32                 Capability;\r
 \r
-  AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\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
+  //\r
+  if ((Capability & EFI_AHCI_CAP_SAM) == 0) {\r
+    AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
+  }\r
 \r
   AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);\r
 \r
@@ -2230,15 +2256,17 @@ AhciModeInitialization (
   }\r
 \r
   //\r
-  // Enable AE before accessing any AHCI registers\r
+  // Collect AHCI controller information\r
   //\r
-  AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
-\r
+  Capability = AhciReadReg (PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
+  \r
   //\r
-  // Collect AHCI controller information\r
+  // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set\r
   //\r
-  Capability           = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
-\r
+  if ((Capability & EFI_AHCI_CAP_SAM) == 0) {\r
+    AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
+  }\r
+  \r
   //\r
   // Get the number of command slots per port supported by this HBA.\r
   //\r