mirror of https://github.com/acidanthera/audk.git
MdeModulePkg/SdMmcPciHcDxe: Refactor command error detection
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1140 Error detection function will now check if the command failure has been caused by one of the errors that can appear randomly on link(CRC error + end bit error). If such an error has been a cause of failure, function will return EFI_CRC_ERROR instead of EFI_DEVICE_ERROR to indicate to the higher level that command has a chance of succeeding if resent. Cc: Hao A Wu <hao.a.wu@intel.com> Cc: Marcin Wojtas <mw@semihalf.com> Cc: Zhichao Gao <zhichao.gao@intel.com> Cc: Liming Gao <liming.gao@intel.com> Signed-off-by: Mateusz Albecki <mateusz.albecki@intel.com> Reviewed-by: Hao A Wu <hao.a.wu@intel.com>
This commit is contained in:
parent
4e2ac8062c
commit
a22f4c34df
MdeModulePkg/Bus/Pci/SdMmcPciHcDxe
|
@ -2137,6 +2137,137 @@ SdMmcExecTrb (
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Performs SW reset based on passed error status mask.
|
||||||
|
|
||||||
|
@param[in] Private Pointer to driver private data.
|
||||||
|
@param[in] Slot Index of the slot to reset.
|
||||||
|
@param[in] ErrIntStatus Error interrupt status mask.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Software reset performed successfully.
|
||||||
|
@retval Other Software reset failed.
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
SdMmcSoftwareReset (
|
||||||
|
IN SD_MMC_HC_PRIVATE_DATA *Private,
|
||||||
|
IN UINT8 Slot,
|
||||||
|
IN UINT16 ErrIntStatus
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UINT8 SwReset;
|
||||||
|
EFI_STATUS Status;
|
||||||
|
|
||||||
|
SwReset = 0;
|
||||||
|
if ((ErrIntStatus & 0x0F) != 0) {
|
||||||
|
SwReset |= BIT1;
|
||||||
|
}
|
||||||
|
if ((ErrIntStatus & 0x70) != 0) {
|
||||||
|
SwReset |= BIT2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = SdMmcHcRwMmio (
|
||||||
|
Private->PciIo,
|
||||||
|
Slot,
|
||||||
|
SD_MMC_HC_SW_RST,
|
||||||
|
FALSE,
|
||||||
|
sizeof (SwReset),
|
||||||
|
&SwReset
|
||||||
|
);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = SdMmcHcWaitMmioSet (
|
||||||
|
Private->PciIo,
|
||||||
|
Slot,
|
||||||
|
SD_MMC_HC_SW_RST,
|
||||||
|
sizeof (SwReset),
|
||||||
|
0xFF,
|
||||||
|
0,
|
||||||
|
SD_MMC_HC_GENERIC_TIMEOUT
|
||||||
|
);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Checks the error status in error status register
|
||||||
|
and issues appropriate software reset as described in
|
||||||
|
SD specification section 3.10.
|
||||||
|
|
||||||
|
@param[in] Private Pointer to driver private data.
|
||||||
|
@param[in] Trb Pointer to currently executing TRB.
|
||||||
|
@param[in] IntStatus Normal interrupt status mask.
|
||||||
|
|
||||||
|
@retval EFI_CRC_ERROR CRC error happened during CMD execution.
|
||||||
|
@retval EFI_SUCCESS No error reported.
|
||||||
|
@retval Others Some other error happened.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
SdMmcCheckAndRecoverErrors (
|
||||||
|
IN SD_MMC_HC_PRIVATE_DATA *Private,
|
||||||
|
IN UINT8 Slot,
|
||||||
|
IN UINT16 IntStatus
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UINT16 ErrIntStatus;
|
||||||
|
EFI_STATUS Status;
|
||||||
|
EFI_STATUS ErrorStatus;
|
||||||
|
|
||||||
|
if ((IntStatus & BIT15) == 0) {
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = SdMmcHcRwMmio (
|
||||||
|
Private->PciIo,
|
||||||
|
Slot,
|
||||||
|
SD_MMC_HC_ERR_INT_STS,
|
||||||
|
TRUE,
|
||||||
|
sizeof (ErrIntStatus),
|
||||||
|
&ErrIntStatus
|
||||||
|
);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// If the data timeout error is reported
|
||||||
|
// but data transfer is signaled as completed we
|
||||||
|
// have to ignore data timeout. We also assume that no
|
||||||
|
// other error is present on the link since data transfer
|
||||||
|
// completed successfully. Error interrupt status
|
||||||
|
// register is going to be reset when the next command
|
||||||
|
// is started.
|
||||||
|
//
|
||||||
|
if (((ErrIntStatus & BIT4) != 0) && ((IntStatus & BIT1) != 0)) {
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// We treat both CMD and DAT CRC errors and
|
||||||
|
// end bits errors as EFI_CRC_ERROR. This will
|
||||||
|
// let higher layer know that the error possibly
|
||||||
|
// happened due to random bus condition and the
|
||||||
|
// command can be retried.
|
||||||
|
//
|
||||||
|
if ((ErrIntStatus & (BIT1 | BIT2 | BIT5 | BIT6)) != 0) {
|
||||||
|
ErrorStatus = EFI_CRC_ERROR;
|
||||||
|
} else {
|
||||||
|
ErrorStatus = EFI_DEVICE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = SdMmcSoftwareReset (Private, Slot, ErrIntStatus);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrorStatus;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Check the TRB execution result.
|
Check the TRB execution result.
|
||||||
|
|
||||||
|
@ -2160,10 +2291,8 @@ SdMmcCheckTrbResult (
|
||||||
UINT32 Response[4];
|
UINT32 Response[4];
|
||||||
UINT64 SdmaAddr;
|
UINT64 SdmaAddr;
|
||||||
UINT8 Index;
|
UINT8 Index;
|
||||||
UINT8 SwReset;
|
|
||||||
UINT32 PioLength;
|
UINT32 PioLength;
|
||||||
|
|
||||||
SwReset = 0;
|
|
||||||
Packet = Trb->Packet;
|
Packet = Trb->Packet;
|
||||||
//
|
//
|
||||||
// Check Trb execution result by reading Normal Interrupt Status register.
|
// Check Trb execution result by reading Normal Interrupt Status register.
|
||||||
|
@ -2179,87 +2308,23 @@ SdMmcCheckTrbResult (
|
||||||
if (EFI_ERROR (Status)) {
|
if (EFI_ERROR (Status)) {
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check if there are any errors reported by host controller
|
||||||
|
// and if neccessary recover the controller before next command is executed.
|
||||||
|
//
|
||||||
|
Status = SdMmcCheckAndRecoverErrors (Private, Trb->Slot, IntStatus);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Check Transfer Complete bit is set or not.
|
// Check Transfer Complete bit is set or not.
|
||||||
//
|
//
|
||||||
if ((IntStatus & BIT1) == BIT1) {
|
if ((IntStatus & BIT1) == BIT1) {
|
||||||
if ((IntStatus & BIT15) == BIT15) {
|
|
||||||
//
|
|
||||||
// Read Error Interrupt Status register to check if the error is
|
|
||||||
// Data Timeout Error.
|
|
||||||
// If yes, treat it as success as Transfer Complete has higher
|
|
||||||
// priority than Data Timeout Error.
|
|
||||||
//
|
|
||||||
Status = SdMmcHcRwMmio (
|
|
||||||
Private->PciIo,
|
|
||||||
Trb->Slot,
|
|
||||||
SD_MMC_HC_ERR_INT_STS,
|
|
||||||
TRUE,
|
|
||||||
sizeof (IntStatus),
|
|
||||||
&IntStatus
|
|
||||||
);
|
|
||||||
if (!EFI_ERROR (Status)) {
|
|
||||||
if ((IntStatus & BIT4) == BIT4) {
|
|
||||||
Status = EFI_SUCCESS;
|
|
||||||
} else {
|
|
||||||
Status = EFI_DEVICE_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// Check if there is a error happened during cmd execution.
|
|
||||||
// If yes, then do error recovery procedure to follow SD Host Controller
|
|
||||||
// Simplified Spec 3.0 section 3.10.1.
|
|
||||||
//
|
|
||||||
if ((IntStatus & BIT15) == BIT15) {
|
|
||||||
Status = SdMmcHcRwMmio (
|
|
||||||
Private->PciIo,
|
|
||||||
Trb->Slot,
|
|
||||||
SD_MMC_HC_ERR_INT_STS,
|
|
||||||
TRUE,
|
|
||||||
sizeof (IntStatus),
|
|
||||||
&IntStatus
|
|
||||||
);
|
|
||||||
if (EFI_ERROR (Status)) {
|
|
||||||
goto Done;
|
|
||||||
}
|
|
||||||
if ((IntStatus & 0x0F) != 0) {
|
|
||||||
SwReset |= BIT1;
|
|
||||||
}
|
|
||||||
if ((IntStatus & 0x70) != 0) {
|
|
||||||
SwReset |= BIT2;
|
|
||||||
}
|
|
||||||
|
|
||||||
Status = SdMmcHcRwMmio (
|
|
||||||
Private->PciIo,
|
|
||||||
Trb->Slot,
|
|
||||||
SD_MMC_HC_SW_RST,
|
|
||||||
FALSE,
|
|
||||||
sizeof (SwReset),
|
|
||||||
&SwReset
|
|
||||||
);
|
|
||||||
if (EFI_ERROR (Status)) {
|
|
||||||
goto Done;
|
|
||||||
}
|
|
||||||
Status = SdMmcHcWaitMmioSet (
|
|
||||||
Private->PciIo,
|
|
||||||
Trb->Slot,
|
|
||||||
SD_MMC_HC_SW_RST,
|
|
||||||
sizeof (SwReset),
|
|
||||||
0xFF,
|
|
||||||
0,
|
|
||||||
SD_MMC_HC_GENERIC_TIMEOUT
|
|
||||||
);
|
|
||||||
if (EFI_ERROR (Status)) {
|
|
||||||
goto Done;
|
|
||||||
}
|
|
||||||
|
|
||||||
Status = EFI_DEVICE_ERROR;
|
|
||||||
goto Done;
|
|
||||||
}
|
|
||||||
//
|
//
|
||||||
// Check if DMA interrupt is signalled for the SDMA transfer.
|
// Check if DMA interrupt is signalled for the SDMA transfer.
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in New Issue