]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Sd / EmmcDxe / EmmcBlockIo.c
index fc705e17d5b489df50d2bde99983900d1b951b18..1b247af57622ce05b50e56a1c1f853a6401d4220 100644 (file)
@@ -1,14 +1,8 @@
 /** @file\r
   The helper functions for BlockIo and BlockIo2 protocol.\r
 \r
-  Copyright (c) 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
-  http://opensource.org/licenses/bsd-license.php\r
-\r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -901,7 +895,10 @@ EmmcReadWrite (
     if (EFI_ERROR (Status)) {\r
       return Status;\r
     }\r
-    DEBUG ((EFI_D_INFO, "Emmc%a(): Part %d Lba 0x%x BlkNo 0x%x Event %p with %r\n", IsRead ? "Read " : "Write", Partition->PartitionType, Lba, BlockNum, Token ? Token->Event : NULL, Status));\r
+    DEBUG ((DEBUG_BLKIO,\r
+      "Emmc%a(): Part %d Lba 0x%x BlkNo 0x%x Event %p with %r\n",\r
+      IsRead ? "Read " : "Write", Partition->PartitionType, Lba, BlockNum,\r
+      (Token != NULL) ? Token->Event : NULL, Status));\r
 \r
     Lba   += BlockNum;\r
     Buffer = (UINT8*)Buffer + BufferSize;\r
@@ -1851,6 +1848,14 @@ EmmcEraseBlock (
   EraseBlock->SdMmcCmdBlk.CommandIndex = EMMC_ERASE;\r
   EraseBlock->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
   EraseBlock->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;\r
+  if ((Device->ExtCsd.SecFeatureSupport & BIT4) != 0) {\r
+    //\r
+    // Perform a Trim operation which applies the erase operation to write blocks\r
+    // instead of erase groups. (Spec JESD84-B51, eMMC Electrical Standard 5.1,\r
+    // Section 6.6.10 and 6.10.4)\r
+    //\r
+    EraseBlock->SdMmcCmdBlk.CommandArgument = 1;\r
+  }\r
 \r
   EraseBlock->IsEnd = IsEnd;\r
   EraseBlock->Token = Token;\r
@@ -1902,6 +1907,43 @@ Error:
   return Status;\r
 }\r
 \r
+/**\r
+  Write zeros to specified blocks.\r
+\r
+  @param[in]  Partition         A pointer to the EMMC_PARTITION instance.\r
+  @param[in]  StartLba          The starting logical block address to write zeros.\r
+  @param[in]  Size              The size in bytes to fill with zeros. This must be a multiple of\r
+                                the physical block size of the device.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcWriteZeros (\r
+  IN  EMMC_PARTITION            *Partition,\r
+  IN  EFI_LBA                   StartLba,\r
+  IN  UINTN                     Size\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  UINT8                                *Buffer;\r
+  UINT32                               MediaId;\r
+\r
+  Buffer = AllocateZeroPool (Size);\r
+  if (Buffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  MediaId = Partition->BlockMedia.MediaId;\r
+\r
+  Status = EmmcReadWrite (Partition, MediaId, StartLba, Buffer, Size, FALSE, NULL);\r
+  FreePool (Buffer);\r
+\r
+  return Status;\r
+}\r
+\r
 /**\r
   Erase a specified number of device blocks.\r
 \r
@@ -1943,7 +1985,13 @@ EmmcEraseBlocks (
   EFI_BLOCK_IO_MEDIA                    *Media;\r
   UINTN                                 BlockSize;\r
   UINTN                                 BlockNum;\r
+  EFI_LBA                               FirstLba;\r
   EFI_LBA                               LastLba;\r
+  EFI_LBA                               StartGroupLba;\r
+  EFI_LBA                               EndGroupLba;\r
+  UINT32                                EraseGroupSize;\r
+  UINT32                                Remainder;\r
+  UINTN                                 WriteZeroSize;\r
   UINT8                                 PartitionConfig;\r
   EMMC_PARTITION                        *Partition;\r
   EMMC_DEVICE                           *Device;\r
@@ -1978,7 +2026,8 @@ EmmcEraseBlocks (
     Token->TransactionStatus = EFI_SUCCESS;\r
   }\r
 \r
-  LastLba = Lba + BlockNum - 1;\r
+  FirstLba = Lba;\r
+  LastLba  = Lba + BlockNum - 1;\r
 \r
   //\r
   // Check if needs to switch partition access.\r
@@ -1994,7 +2043,96 @@ EmmcEraseBlocks (
     Device->ExtCsd.PartitionConfig = PartitionConfig;\r
   }\r
 \r
-  Status = EmmcEraseBlockStart (Partition, Lba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);\r
+  if ((Device->ExtCsd.SecFeatureSupport & BIT4) == 0) {\r
+    //\r
+    // If the Trim operation is not supported by the device, handle the erase\r
+    // of blocks that do not form a complete erase group separately.\r
+    //\r
+    EraseGroupSize = This->EraseLengthGranularity;\r
+\r
+    DivU64x32Remainder (FirstLba, EraseGroupSize, &Remainder);\r
+    StartGroupLba = (Remainder == 0) ? FirstLba : (FirstLba + EraseGroupSize - Remainder);\r
+\r
+    DivU64x32Remainder (LastLba + 1, EraseGroupSize, &Remainder);\r
+    EndGroupLba = LastLba + 1 - Remainder;\r
+\r
+    //\r
+    // If the size to erase is smaller than the erase group size, the whole\r
+    // erase operation is performed by writting zeros.\r
+    //\r
+    if (BlockNum < EraseGroupSize) {\r
+      Status = EmmcWriteZeros (Partition, FirstLba, Size);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      DEBUG ((\r
+        DEBUG_INFO,\r
+        "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",\r
+        Lba,\r
+        BlockNum,\r
+        (Token != NULL) ? Token->Event : NULL,\r
+        Status\r
+        ));\r
+\r
+      if ((Token != NULL) && (Token->Event != NULL)) {\r
+        Token->TransactionStatus = EFI_SUCCESS;\r
+        gBS->SignalEvent (Token->Event);\r
+      }\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    //\r
+    // If the starting LBA to erase is not aligned with the start of an erase\r
+    // group, write zeros to erase the data from starting LBA to the end of the\r
+    // current erase group.\r
+    //\r
+    if (StartGroupLba > FirstLba) {\r
+      WriteZeroSize = (UINTN)(StartGroupLba - FirstLba) * BlockSize;\r
+      Status = EmmcWriteZeros (Partition, FirstLba, WriteZeroSize);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+    }\r
+\r
+    //\r
+    // If the ending LBA to erase is not aligned with the end of an erase\r
+    // group, write zeros to erase the data from the start of the erase group\r
+    // to the ending LBA.\r
+    //\r
+    if (EndGroupLba <= LastLba) {\r
+      WriteZeroSize = (UINTN)(LastLba + 1 - EndGroupLba) * BlockSize;\r
+      Status = EmmcWriteZeros (Partition, EndGroupLba, WriteZeroSize);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Check whether there is erase group to erase.\r
+    //\r
+    if (EndGroupLba <= StartGroupLba) {\r
+      DEBUG ((\r
+        DEBUG_INFO,\r
+        "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",\r
+        Lba,\r
+        BlockNum,\r
+        (Token != NULL) ? Token->Event : NULL,\r
+        Status\r
+        ));\r
+\r
+      if ((Token != NULL) && (Token->Event != NULL)) {\r
+        Token->TransactionStatus = EFI_SUCCESS;\r
+        gBS->SignalEvent (Token->Event);\r
+      }\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    FirstLba = StartGroupLba;\r
+    LastLba  = EndGroupLba - 1;\r
+  }\r
+\r
+  Status = EmmcEraseBlockStart (Partition, FirstLba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
@@ -2009,7 +2147,14 @@ EmmcEraseBlocks (
     return Status;\r
   }\r
 \r
-  DEBUG ((EFI_D_ERROR, "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", Lba, BlockNum, Token->Event, Status));\r
+  DEBUG ((\r
+    DEBUG_INFO,\r
+    "EmmcEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",\r
+    Lba,\r
+    BlockNum,\r
+    (Token != NULL) ? Token->Event : NULL,\r
+    Status\r
+    ));\r
 \r
   return Status;\r
 }\r