/** @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
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
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
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
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
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
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
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