EmbeddedPkg/MmcDxe: expand to support multiple blocks
authorHaojian Zhuang <haojian.zhuang@linaro.org>
Wed, 23 Nov 2016 13:36:24 +0000 (21:36 +0800)
committerArd Biesheuvel <ard.biesheuvel@linaro.org>
Thu, 24 Nov 2016 16:29:04 +0000 (16:29 +0000)
Make use of DMA to transfer multiple blocks at one time. It could
improve the performance on MMC/SD driver.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
Tested-by: Ryan Harkin <ryan.harkin@linaro.org>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
EmbeddedPkg/Universal/MmcDxe/Mmc.h
EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c

index c96ff2e..8a7d5a3 100644 (file)
 \r
 #define MMC_OCR_POWERUP             0x80000000\r
 \r
+#define MMC_OCR_ACCESS_MASK         0x3     /* bit[30-29] */\r
+#define MMC_OCR_ACCESS_BYTE         0x1     /* bit[29] */\r
+#define MMC_OCR_ACCESS_SECTOR       0x2     /* bit[30] */\r
+\r
 #define MMC_CSD_GET_CCC(Response)    (Response[2] >> 20)\r
 #define MMC_CSD_GET_TRANSPEED(Response)    (Response[3] & 0xFF)\r
 #define MMC_CSD_GET_READBLLEN(Response)    ((Response[2] >> 16) & 0xF)\r
index 0e1ef57..403db96 100644 (file)
@@ -126,6 +126,96 @@ MmcStopTransmission (
 #define MMCI0_BLOCKLEN 512\r
 #define MMCI0_TIMEOUT  10000\r
 \r
+STATIC\r
+EFI_STATUS\r
+MmcTransferBlock (\r
+  IN EFI_BLOCK_IO_PROTOCOL    *This,\r
+  IN UINTN                    Cmd,\r
+  IN UINTN                    Transfer,\r
+  IN UINT32                   MediaId,\r
+  IN EFI_LBA                  Lba,\r
+  IN UINTN                    BufferSize,\r
+  OUT VOID                    *Buffer\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  UINTN                   CmdArg;\r
+  INTN                    Timeout;\r
+  UINT32                  Response[4];\r
+  MMC_HOST_INSTANCE       *MmcHostInstance;\r
+  EFI_MMC_HOST_PROTOCOL   *MmcHost;\r
+\r
+  MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This);\r
+  MmcHost = MmcHostInstance->MmcHost;\r
+\r
+  //Set command argument based on the card access mode (Byte mode or Block mode)\r
+  if ((MmcHostInstance->CardInfo.OCRData.AccessMode & MMC_OCR_ACCESS_MASK) ==\r
+      MMC_OCR_ACCESS_SECTOR) {\r
+    CmdArg = Lba;\r
+  } else {\r
+    CmdArg = Lba * This->Media->BlockSize;\r
+  }\r
+\r
+  Status = MmcHost->SendCommand (MmcHost, Cmd, CmdArg);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "%a(MMC_CMD%d): Error %r\n", __func__, Cmd, Status));\r
+    return Status;\r
+  }\r
+\r
+  if (Transfer == MMC_IOBLOCKS_READ) {\r
+    // Read Data\r
+    Status = MmcHost->ReadBlockData (MmcHost, Lba, BufferSize, Buffer);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_BLKIO, "%a(): Error Read Block Data and Status = %r\n", __func__, Status));\r
+      MmcStopTransmission (MmcHost);\r
+      return Status;\r
+    }\r
+    Status = MmcNotifyState (MmcHostInstance, MmcProgrammingState);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "%a() : Error MmcProgrammingState\n", __func__));\r
+      return Status;\r
+    }\r
+  } else {\r
+    // Write Data\r
+    Status = MmcHost->WriteBlockData (MmcHost, Lba, BufferSize, Buffer);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_BLKIO, "%a(): Error Write Block Data and Status = %r\n", __func__, Status));\r
+      MmcStopTransmission (MmcHost);\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  // Command 13 - Read status and wait for programming to complete (return to tran)\r
+  Timeout = MMCI0_TIMEOUT;\r
+  CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
+  Response[0] = 0;\r
+  while(!(Response[0] & MMC_R0_READY_FOR_DATA)\r
+        && (MMC_R0_CURRENTSTATE (Response) != MMC_R0_STATE_TRAN)\r
+        && Timeout--) {\r
+    Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);\r
+    if (!EFI_ERROR (Status)) {\r
+      MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);\r
+      if (Response[0] & MMC_R0_READY_FOR_DATA) {\r
+        break;  // Prevents delay once finished\r
+      }\r
+    }\r
+  }\r
+\r
+  if (BufferSize > This->Media->BlockSize) {\r
+    Status = MmcHost->SendCommand (MmcHost, MMC_CMD12, 0);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_BLKIO, "%a(): Error and Status:%r\n", __func__, Status));\r
+    }\r
+  }\r
+\r
+  Status = MmcNotifyState (MmcHostInstance, MmcTransferState);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "MmcIoBlocks() : Error MmcTransferState\n"));\r
+    return Status;\r
+  }\r
+  return Status;\r
+}\r
+\r
 EFI_STATUS\r
 MmcIoBlocks (\r
   IN EFI_BLOCK_IO_PROTOCOL    *This,\r
@@ -145,6 +235,7 @@ MmcIoBlocks (
   EFI_MMC_HOST_PROTOCOL   *MmcHost;\r
   UINTN                   BytesRemainingToBeTransfered;\r
   UINTN                   BlockCount;\r
+  UINTN                   ConsumeSize;\r
 \r
   BlockCount = 1;\r
   MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This);\r
@@ -165,6 +256,10 @@ MmcIoBlocks (
     return EFI_NO_MEDIA;\r
   }\r
 \r
+  if (MMC_HOST_HAS_ISMULTIBLOCK(MmcHost) && MmcHost->IsMultiBlock(MmcHost)) {\r
+    BlockCount = (BufferSize + This->Media->BlockSize - 1) / This->Media->BlockSize;\r
+  }\r
+\r
   // All blocks must be within the device\r
   if ((Lba + (BufferSize / This->Media->BlockSize)) > (This->Media->LastBlock + 1)) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -210,75 +305,38 @@ MmcIoBlocks (
       return EFI_NOT_READY;\r
     }\r
 \r
-    //Set command argument based on the card access mode (Byte mode or Block mode)\r
-    if (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1) {\r
-      CmdArg = Lba;\r
-    } else {\r
-      CmdArg = Lba * This->Media->BlockSize;\r
-    }\r
-\r
     if (Transfer == MMC_IOBLOCKS_READ) {\r
-      // Read a single block\r
-      Cmd = MMC_CMD17;\r
-    } else {\r
-      // Write a single block\r
-      Cmd = MMC_CMD24;\r
-    }\r
-    Status = MmcHost->SendCommand (MmcHost, Cmd, CmdArg);\r
-    if (EFI_ERROR (Status)) {\r
-      DEBUG ((EFI_D_ERROR, "MmcIoBlocks(MMC_CMD%d): Error %r\n", Cmd, Status));\r
-      return Status;\r
-    }\r
-\r
-    if (Transfer == MMC_IOBLOCKS_READ) {\r
-      // Read one block of Data\r
-      Status = MmcHost->ReadBlockData (MmcHost, Lba, This->Media->BlockSize, Buffer);\r
-      if (EFI_ERROR (Status)) {\r
-        DEBUG ((EFI_D_BLKIO, "MmcIoBlocks(): Error Read Block Data and Status = %r\n", Status));\r
-        MmcStopTransmission (MmcHost);\r
-        return Status;\r
-      }\r
-      Status = MmcNotifyState (MmcHostInstance, MmcProgrammingState);\r
-      if (EFI_ERROR (Status)) {\r
-        DEBUG ((EFI_D_ERROR, "MmcIoBlocks() : Error MmcProgrammingState\n"));\r
-        return Status;\r
+      if (BlockCount == 1) {\r
+        // Read a single block\r
+        Cmd = MMC_CMD17;\r
+      } else {\r
+       // Read multiple blocks\r
+       Cmd = MMC_CMD18;\r
       }\r
     } else {\r
-      // Write one block of Data\r
-      Status = MmcHost->WriteBlockData (MmcHost, Lba, This->Media->BlockSize, Buffer);\r
-      if (EFI_ERROR (Status)) {\r
-        DEBUG ((EFI_D_BLKIO, "MmcIoBlocks(): Error Write Block Data and Status = %r\n", Status));\r
-        MmcStopTransmission (MmcHost);\r
-        return Status;\r
+      if (BlockCount == 1) {\r
+        // Write a single block\r
+        Cmd = MMC_CMD24;\r
+      } else {\r
+       // Write multiple blocks\r
+       Cmd = MMC_CMD25;\r
       }\r
     }\r
 \r
-    // Command 13 - Read status and wait for programming to complete (return to tran)\r
-    Timeout = MMCI0_TIMEOUT;\r
-    CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
-    Response[0] = 0;\r
-    while(   (!(Response[0] & MMC_R0_READY_FOR_DATA))\r
-          && (MMC_R0_CURRENTSTATE (Response) != MMC_R0_STATE_TRAN)\r
-          && Timeout--) {\r
-      Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);\r
-      if (!EFI_ERROR (Status)) {\r
-        MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);\r
-        if ((Response[0] & MMC_R0_READY_FOR_DATA)) {\r
-          break;  // Prevents delay once finished\r
-        }\r
-      }\r
-      gBS->Stall (1);\r
+    ConsumeSize = BlockCount * This->Media->BlockSize;\r
+    if (BytesRemainingToBeTransfered < ConsumeSize) {\r
+      ConsumeSize = BytesRemainingToBeTransfered;\r
     }\r
-\r
-    Status = MmcNotifyState (MmcHostInstance, MmcTransferState);\r
+    Status = MmcTransferBlock (This, Cmd, Transfer, MediaId, Lba, ConsumeSize, Buffer);\r
     if (EFI_ERROR (Status)) {\r
-      DEBUG ((EFI_D_ERROR, "MmcIoBlocks() : Error MmcTransferState\n"));\r
-      return Status;\r
+      DEBUG ((EFI_D_ERROR, "%a(): Failed to transfer block and Status:%r\n", __func__, Status));\r
     }\r
 \r
-    BytesRemainingToBeTransfered -= This->Media->BlockSize;\r
-    Lba    += BlockCount;\r
-    Buffer = (UINT8 *)Buffer + This->Media->BlockSize;\r
+    BytesRemainingToBeTransfered -= ConsumeSize;\r
+    if (BytesRemainingToBeTransfered > 0) {\r
+      Lba    += BlockCount;\r
+      Buffer = (UINT8 *)Buffer + ConsumeSize;\r
+    }\r
   }\r
 \r
   return EFI_SUCCESS;\r