Skip to content

Commit

Permalink
RPi3: MmcDxe: block I/O cleanup
Browse files Browse the repository at this point in the history
When building without NDEBUG, validate that
written blocks are written.

Signed-off-by: Andrei Warkentin <andrey.warkentin@gmail.com>
  • Loading branch information
andreiw committed Jul 8, 2018
1 parent da62af2 commit bdea35d
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 35 deletions.
5 changes: 5 additions & 0 deletions Drivers/MmcDxe/Mmc.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@
#define MMC_R0_STATE_STDBY 3
#define MMC_R0_STATE_TRAN 4
#define MMC_R0_STATE_DATA 5
#define MMC_R0_STATE_RECV 6
#define MMC_R0_STATE_PROG 7
#define MMC_R0_STATE_DIS 8


#define EMMC_CMD6_ARG_ACCESS(x) (((x) & 0x3) << 24)
#define EMMC_CMD6_ARG_INDEX(x) (((x) & 0xFF) << 16)
Expand Down Expand Up @@ -111,6 +115,7 @@ typedef struct {
typedef struct {
UINT32 NOT_USED; // 1 [0:0]
UINT32 CRC; // CRC7 checksum [7:1]

UINT32 MDT; // Manufacturing date [19:8]
UINT32 RESERVED_1; // Reserved [23:20]
UINT32 PSN; // Product serial number [55:24]
Expand Down
172 changes: 137 additions & 35 deletions Drivers/MmcDxe/MmcBlockIo.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,88 @@
#define MMCI0_BLOCKLEN 512
#define MMCI0_TIMEOUT 1000

STATIC
EFI_STATUS
R1TranAndReady(UINT32 *Response)
{
if ((*Response & MMC_R0_READY_FOR_DATA) != 0 &&
MMC_R0_CURRENTSTATE(Response) == MMC_R0_STATE_TRAN) {
return EFI_SUCCESS;
}

return EFI_NOT_READY;
}

#ifndef NDEBUG
STATIC
EFI_STATUS
ValidateWrittenBlockCount(
IN MMC_HOST_INSTANCE *MmcHostInstance,
IN UINTN Count
)
{
UINT32 R1;
UINT8 Data[4];
EFI_STATUS Status;
UINT32 BlocksWritten;
EFI_MMC_HOST_PROTOCOL *MmcHost = MmcHostInstance->MmcHost;

if (MmcHostInstance->CardInfo.CardType == MMC_CARD ||
MmcHostInstance->CardInfo.CardType == MMC_CARD_HIGH ||
MmcHostInstance->CardInfo.CardType == EMMC_CARD) {
/*
* Not on MMC.
*/
return EFI_SUCCESS;
}

Status = MmcHost->SendCommand (MmcHost, MMC_CMD55,
MmcHostInstance->CardInfo.RCA << 16);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a(%u): error: %r\n",
__FUNCTION__, __LINE__, Status));
return Status;
}

Status = MmcHost->SendCommand (MmcHost, MMC_ACMD22, 0);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a(%u): error: %r\n",
__FUNCTION__, __LINE__, Status));
return Status;
}

MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, &R1);
Status = R1TranAndReady(&R1);
if (EFI_ERROR (Status)) {
return Status;
}

// Read Data
Status = MmcHost->ReadBlockData (MmcHost, 0, sizeof(Data),
(VOID *) Data);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a(%u): error: %r\n",
__FUNCTION__, __LINE__, Status));
return Status;
}

/*
* Big Endian.
*/
BlocksWritten = ((UINT32) Data[0] << 24) |
((UINT32) Data[1] << 16) |
((UINT32) Data[2] << 8) |
((UINT32) Data[3] << 0);
if (BlocksWritten != Count) {
DEBUG ((DEBUG_ERROR, "%a(%u): expected %u != gotten %u\n",
__FUNCTION__, __LINE__, Count, BlocksWritten));
return EFI_DEVICE_ERROR;
}

return EFI_SUCCESS;
}
#endif /* NDEBUG */

STATIC
EFI_STATUS
WaitUntilTran(
Expand All @@ -30,26 +112,27 @@ WaitUntilTran(
EFI_STATUS Status = EFI_SUCCESS;
EFI_MMC_HOST_PROTOCOL *MmcHost = MmcHostInstance->MmcHost;

Response[0] = 0;
Timeout = MMCI0_TIMEOUT;
while(!EFI_ERROR (Status)
&& !(Response[0] & MMC_R0_READY_FOR_DATA)
&& (MMC_R0_CURRENTSTATE(Response) != MMC_R0_STATE_TRAN)
&& Timeout--) {
while(Timeout--) {
Status = MmcHost->SendCommand (MmcHost, MMC_CMD13,
MmcHostInstance->CardInfo.RCA << 16);
if (!EFI_ERROR (Status)) {
MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);
if (Response[0] & MMC_R0_READY_FOR_DATA) {
break;
}
if (EFI_ERROR(Status)) {
DEBUG ((EFI_D_ERROR, "%a(%u) CMD13 failed: %r\n",
__FUNCTION__, __LINE__, Status));
break;
}

MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);
Status = R1TranAndReady(Response);
if (!EFI_ERROR(Status)) {
break;
}

gBS->Stall(1000);
}

if (0 == Timeout) {
DEBUG ((EFI_D_ERROR, "Card is busy\n"));
DEBUG ((EFI_D_ERROR, "%a(%u) card is busy\n", __FUNCTION__, __LINE__));
return EFI_NOT_READY;
}

Expand Down Expand Up @@ -141,7 +224,6 @@ MmcTransferBlock (
)
{
EFI_STATUS Status;
UINT32 Response[4];
MMC_HOST_INSTANCE *MmcHostInstance;
EFI_MMC_HOST_PROTOCOL *MmcHost;
UINTN CmdArg;
Expand All @@ -165,47 +247,65 @@ MmcTransferBlock (
}

if (Transfer == MMC_IOBLOCKS_READ) {
// Read Data
Status = MmcHost->ReadBlockData (MmcHost, Lba, BufferSize, Buffer);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_BLKIO, "%a(): Error Read Block Data and Status = %r\n", __func__, Status));
MmcStopTransmission (MmcHost);
return Status;
}
Status = MmcNotifyState (MmcHostInstance, MmcProgrammingState);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "%a() : Error MmcProgrammingState\n", __func__));
return Status;
}
} else {
// Write Data
Status = MmcHost->WriteBlockData (MmcHost, Lba, BufferSize, Buffer);
if (!EFI_ERROR (Status)) {
Status = MmcNotifyState (MmcHostInstance, MmcProgrammingState);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "%a() : Error MmcProgrammingState\n", __func__));
return Status;
}
}
}

if (EFI_ERROR (Status) ||
BufferSize > This->Media->BlockSize) {
/*
* CMD12 needs to be set for multiblock (to transition from
* RECV to PROG) or for errors.
*/
EFI_STATUS Status2 = MmcStopTransmission (MmcHost);
if (EFI_ERROR (Status2)) {
DEBUG ((EFI_D_ERROR, "MmcIoBlocks() : CMD12 error on Status %r: %r\n",
Status, Status2));
return Status2;
}

if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_BLKIO, "%a(): Error Write Block Data and Status = %r\n", __func__, Status));
MmcStopTransmission (MmcHost);
DEBUG ((EFI_D_BLKIO, "%a(): Error %a Block Data and Status = %r\n",
__func__, Transfer == MMC_IOBLOCKS_READ ? "Read" : "Write",
Status));
return Status;
}

ASSERT (Cmd == MMC_CMD25 || Cmd == MMC_CMD18);
}

// Wait for programming to complete, returning to transfer state.
//
// For reads, should be already in TRAN. For writes, wait
// until programming finishes.
//
Status = WaitUntilTran(MmcHostInstance);
if (EFI_ERROR (Status)) {
DEBUG((EFI_D_ERROR, "WaitUntilTran failed\n"));
return Status;
}

if (BufferSize > This->Media->BlockSize) {
Status = MmcHost->SendCommand (MmcHost, MMC_CMD12, 0);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_BLKIO, "%a(): Error and Status:%r\n", __func__, Status));
}
MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1b, Response);
}

Status = MmcNotifyState (MmcHostInstance, MmcTransferState);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "MmcIoBlocks() : Error MmcTransferState\n"));
return Status;
}

#ifndef NDEBUG
if (Transfer != MMC_IOBLOCKS_READ) {
Status = ValidateWrittenBlockCount (MmcHostInstance,
BufferSize /
This->Media->BlockSize);
}
#endif /* NDEBUG */

return Status;
}

Expand Down Expand Up @@ -304,9 +404,11 @@ MmcIoBlocks (
if (BytesRemainingToBeTransfered < ConsumeSize) {
ConsumeSize = BytesRemainingToBeTransfered;
}

Status = MmcTransferBlock (This, Cmd, Transfer, MediaId, Lba, ConsumeSize, Buffer);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "%a(): Failed to transfer block and Status:%r\n", __func__, Status));
return Status;
}

BytesRemainingToBeTransfered -= ConsumeSize;
Expand Down
1 change: 1 addition & 0 deletions Include/Protocol/MmcHost.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ typedef UINT32 MMC_CMD;
#define MMC_CMD24 (MMC_INDX(24) | MMC_CMD_WAIT_RESPONSE)
#define MMC_CMD25 (MMC_INDX(25) | MMC_CMD_WAIT_RESPONSE)
#define MMC_CMD55 (MMC_INDX(55) | MMC_CMD_WAIT_RESPONSE)
#define MMC_ACMD22 (MMC_INDX(22) | MMC_CMD_WAIT_RESPONSE)
#define MMC_ACMD41 (MMC_INDX(41) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_NO_CRC_RESPONSE)
#define MMC_ACMD51 (MMC_INDX(51) | MMC_CMD_WAIT_RESPONSE)

Expand Down

0 comments on commit bdea35d

Please sign in to comment.