blob: 783e548d2aed6afec644b813ffcf7485dc5d982b [file] [log] [blame]
andrewfish1bfda052011-02-02 22:35:30 +00001/** @file
2 Diagnostics Protocol implementation for the MMC DXE driver
3
Olivier Martin5c5a34d2014-01-09 19:15:06 +00004 Copyright (c) 2011-2014, ARM Limited. All rights reserved.
andrewfish1bfda052011-02-02 22:35:30 +00005
Ronald Cron3402aac2014-08-19 13:29:52 +00006 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
andrewfish1bfda052011-02-02 22:35:30 +000013
14**/
15
16#include <Uefi.h>
17#include <Library/DebugLib.h>
18#include <Library/BaseMemoryLib.h>
19#include <Library/MemoryAllocationLib.h>
Olivier Martinc8af31e2013-09-23 09:43:51 +000020#include <Library/BaseLib.h>
andrewfish1bfda052011-02-02 22:35:30 +000021
22#include "Mmc.h"
23
24#define DIAGNOSTIC_LOGBUFFER_MAXCHAR 1024
25
26CHAR16* mLogBuffer = NULL;
27UINTN mLogRemainChar = 0;
28
oliviermartin11c20f42011-09-22 22:53:54 +000029CHAR16*
30DiagnosticInitLog (
31 UINTN MaxBufferChar
32 )
33{
34 mLogRemainChar = MaxBufferChar;
Olivier Martinc8af31e2013-09-23 09:43:51 +000035 mLogBuffer = AllocatePool ((UINTN)MaxBufferChar * sizeof (CHAR16));
oliviermartin11c20f42011-09-22 22:53:54 +000036 return mLogBuffer;
andrewfish1bfda052011-02-02 22:35:30 +000037}
38
oliviermartin11c20f42011-09-22 22:53:54 +000039UINTN
40DiagnosticLog (
41 CONST CHAR16* Str
42 )
43{
44 UINTN len = StrLen (Str);
45 if (len <= mLogRemainChar) {
46 mLogRemainChar -= len;
47 StrCpy (mLogBuffer, Str);
48 mLogBuffer += len;
49 return len;
50 } else {
51 return 0;
52 }
andrewfish1bfda052011-02-02 22:35:30 +000053}
54
oliviermartin11c20f42011-09-22 22:53:54 +000055VOID
56GenerateRandomBuffer (
57 VOID* Buffer,
58 UINTN BufferSize
59 )
60{
61 UINT64 i;
62 UINT64* Buffer64 = (UINT64*)Buffer;
andrewfish1bfda052011-02-02 22:35:30 +000063
oliviermartin11c20f42011-09-22 22:53:54 +000064 for (i = 0; i < (BufferSize >> 3); i++) {
65 *Buffer64 = i | (~i << 32);
66 Buffer64++;
67 }
andrewfish1bfda052011-02-02 22:35:30 +000068}
69
oliviermartin11c20f42011-09-22 22:53:54 +000070BOOLEAN
71CompareBuffer (
72 VOID *BufferA,
73 VOID *BufferB,
74 UINTN BufferSize
75 )
76{
77 UINTN i;
78 UINT64* BufferA64 = (UINT64*)BufferA;
79 UINT64* BufferB64 = (UINT64*)BufferB;
andrewfish1bfda052011-02-02 22:35:30 +000080
oliviermartin11c20f42011-09-22 22:53:54 +000081 for (i = 0; i < (BufferSize >> 3); i++) {
82 if (*BufferA64 != *BufferB64) {
Olivier Martinc8af31e2013-09-23 09:43:51 +000083 DEBUG ((EFI_D_ERROR, "CompareBuffer: Error at %i", i));
84 DEBUG ((EFI_D_ERROR, "(0x%lX) != (0x%lX)\n", *BufferA64, *BufferB64));
oliviermartin11c20f42011-09-22 22:53:54 +000085 return FALSE;
andrewfish1bfda052011-02-02 22:35:30 +000086 }
oliviermartin11c20f42011-09-22 22:53:54 +000087 BufferA64++;
88 BufferB64++;
89 }
90 return TRUE;
andrewfish1bfda052011-02-02 22:35:30 +000091}
92
oliviermartin11c20f42011-09-22 22:53:54 +000093EFI_STATUS
94MmcReadWriteDataTest (
95 MMC_HOST_INSTANCE *MmcHostInstance,
96 EFI_LBA Lba,
97 UINTN BufferSize
98 )
99{
100 VOID *BackBuffer;
101 VOID *WriteBuffer;
102 VOID *ReadBuffer;
103 EFI_STATUS Status;
andrewfish1bfda052011-02-02 22:35:30 +0000104
oliviermartin11c20f42011-09-22 22:53:54 +0000105 // Check if a Media is Present
106 if (!MmcHostInstance->BlockIo.Media->MediaPresent) {
107 DiagnosticLog (L"ERROR: No Media Present\n");
108 return EFI_NO_MEDIA;
109 }
andrewfish1bfda052011-02-02 22:35:30 +0000110
oliviermartin11c20f42011-09-22 22:53:54 +0000111 if (MmcHostInstance->State != MmcTransferState) {
112 DiagnosticLog (L"ERROR: Not ready for Transfer state\n");
113 return EFI_NOT_READY;
114 }
andrewfish1bfda052011-02-02 22:35:30 +0000115
oliviermartin11c20f42011-09-22 22:53:54 +0000116 BackBuffer = AllocatePool (BufferSize);
117 WriteBuffer = AllocatePool (BufferSize);
118 ReadBuffer = AllocatePool (BufferSize);
andrewfish1bfda052011-02-02 22:35:30 +0000119
oliviermartin11c20f42011-09-22 22:53:54 +0000120 // Read (and save) buffer at a specific location
121 Status = MmcReadBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,BackBuffer);
122 if (Status != EFI_SUCCESS) {
123 DiagnosticLog (L"ERROR: Fail to Read Block (1)\n");
124 return Status;
125 }
andrewfish1bfda052011-02-02 22:35:30 +0000126
oliviermartin11c20f42011-09-22 22:53:54 +0000127 // Write buffer at the same location
128 GenerateRandomBuffer (WriteBuffer,BufferSize);
129 Status = MmcWriteBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,WriteBuffer);
130 if (Status != EFI_SUCCESS) {
131 DiagnosticLog (L"ERROR: Fail to Write Block (1)\n");
132 return Status;
133 }
andrewfish1bfda052011-02-02 22:35:30 +0000134
oliviermartin11c20f42011-09-22 22:53:54 +0000135 // Read the buffer at the same location
136 Status = MmcReadBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,ReadBuffer);
137 if (Status != EFI_SUCCESS) {
138 DiagnosticLog (L"ERROR: Fail to Read Block (2)\n");
139 return Status;
140 }
andrewfish1bfda052011-02-02 22:35:30 +0000141
oliviermartin11c20f42011-09-22 22:53:54 +0000142 // Check that is conform
143 if (!CompareBuffer (ReadBuffer,WriteBuffer,BufferSize)) {
144 DiagnosticLog (L"ERROR: Fail to Read/Write Block (1)\n");
145 return EFI_INVALID_PARAMETER;
146 }
andrewfish1bfda052011-02-02 22:35:30 +0000147
oliviermartin11c20f42011-09-22 22:53:54 +0000148 // Restore content at the original location
149 Status = MmcWriteBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,BackBuffer);
150 if (Status != EFI_SUCCESS) {
151 DiagnosticLog (L"ERROR: Fail to Write Block (2)\n");
152 return Status;
153 }
andrewfish1bfda052011-02-02 22:35:30 +0000154
oliviermartin11c20f42011-09-22 22:53:54 +0000155 // Read the restored content
156 Status = MmcReadBlocks (&(MmcHostInstance->BlockIo), MmcHostInstance->BlockIo.Media->MediaId,Lba,BufferSize,ReadBuffer);
157 if (Status != EFI_SUCCESS) {
158 DiagnosticLog (L"ERROR: Fail to Read Block (3)\n");
159 return Status;
160 }
andrewfish1bfda052011-02-02 22:35:30 +0000161
oliviermartin11c20f42011-09-22 22:53:54 +0000162 // Check the content is correct
163 if (!CompareBuffer (ReadBuffer,BackBuffer,BufferSize)) {
164 DiagnosticLog (L"ERROR: Fail to Read/Write Block (2)\n");
165 return EFI_INVALID_PARAMETER;
166 }
167
168 return EFI_SUCCESS;
andrewfish1bfda052011-02-02 22:35:30 +0000169}
170
171EFI_STATUS
172EFIAPI
173MmcDriverDiagnosticsRunDiagnostics (
174 IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *This,
175 IN EFI_HANDLE ControllerHandle,
176 IN EFI_HANDLE ChildHandle OPTIONAL,
177 IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType,
178 IN CHAR8 *Language,
179 OUT EFI_GUID **ErrorType,
180 OUT UINTN *BufferSize,
181 OUT CHAR16 **Buffer
182 )
183{
oliviermartin11c20f42011-09-22 22:53:54 +0000184 LIST_ENTRY *CurrentLink;
185 MMC_HOST_INSTANCE *MmcHostInstance;
186 EFI_STATUS Status;
andrewfish1bfda052011-02-02 22:35:30 +0000187
oliviermartin11c20f42011-09-22 22:53:54 +0000188 if ((Language == NULL) ||
189 (ErrorType == NULL) ||
190 (Buffer == NULL) ||
191 (ControllerHandle == NULL) ||
192 (BufferSize == NULL)) {
193 return EFI_INVALID_PARAMETER;
194 }
andrewfish1bfda052011-02-02 22:35:30 +0000195
Olivier Martinc8af31e2013-09-23 09:43:51 +0000196 // Check Language is supported (i.e. is "en-*" - only English is supported)
197 if (AsciiStrnCmp (Language, "en", 2) != 0) {
198 return EFI_UNSUPPORTED;
199 }
200
oliviermartin11c20f42011-09-22 22:53:54 +0000201 Status = EFI_SUCCESS;
202 *ErrorType = NULL;
203 *BufferSize = DIAGNOSTIC_LOGBUFFER_MAXCHAR;
204 *Buffer = DiagnosticInitLog (DIAGNOSTIC_LOGBUFFER_MAXCHAR);
andrewfish1bfda052011-02-02 22:35:30 +0000205
oliviermartin11c20f42011-09-22 22:53:54 +0000206 DiagnosticLog (L"MMC Driver Diagnostics\n");
andrewfish1bfda052011-02-02 22:35:30 +0000207
Olivier Martin5c5a34d2014-01-09 19:15:06 +0000208 // Find the MMC Host instance on which we have been asked to run diagnostics
209 MmcHostInstance = NULL;
oliviermartin11c20f42011-09-22 22:53:54 +0000210 CurrentLink = mMmcHostPool.ForwardLink;
211 while (CurrentLink != NULL && CurrentLink != &mMmcHostPool && (Status == EFI_SUCCESS)) {
Olivier Martin5c5a34d2014-01-09 19:15:06 +0000212 MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK(CurrentLink);
213 ASSERT(MmcHostInstance != NULL);
214 if (MmcHostInstance->MmcHandle == ControllerHandle) {
215 break;
216 }
oliviermartin11c20f42011-09-22 22:53:54 +0000217 CurrentLink = CurrentLink->ForwardLink;
218 }
andrewfish1bfda052011-02-02 22:35:30 +0000219
Olivier Martin5c5a34d2014-01-09 19:15:06 +0000220 // If we didn't find the controller, return EFI_UNSUPPORTED
221 if ((MmcHostInstance == NULL)
222 || (MmcHostInstance->MmcHandle != ControllerHandle)) {
223 return EFI_UNSUPPORTED;
224 }
225
226 // LBA=1 Size=BlockSize
227 DiagnosticLog (L"MMC Driver Diagnostics - Test: First Block\n");
228 Status = MmcReadWriteDataTest (MmcHostInstance, 1, MmcHostInstance->BlockIo.Media->BlockSize);
229
230 // LBA=2 Size=BlockSize
231 DiagnosticLog (L"MMC Driver Diagnostics - Test: Second Block\n");
232 Status = MmcReadWriteDataTest (MmcHostInstance, 2, MmcHostInstance->BlockIo.Media->BlockSize);
233
234 // LBA=10 Size=BlockSize
235 DiagnosticLog (L"MMC Driver Diagnostics - Test: Any Block\n");
236 Status = MmcReadWriteDataTest (MmcHostInstance, MmcHostInstance->BlockIo.Media->LastBlock >> 1, MmcHostInstance->BlockIo.Media->BlockSize);
237
238 // LBA=LastBlock Size=BlockSize
239 DiagnosticLog (L"MMC Driver Diagnostics - Test: Last Block\n");
240 Status = MmcReadWriteDataTest (MmcHostInstance, MmcHostInstance->BlockIo.Media->LastBlock, MmcHostInstance->BlockIo.Media->BlockSize);
241
242 // LBA=1 Size=2*BlockSize
243 DiagnosticLog (L"MMC Driver Diagnostics - Test: First Block / 2 BlockSSize\n");
244 Status = MmcReadWriteDataTest (MmcHostInstance, 1, 2 * MmcHostInstance->BlockIo.Media->BlockSize);
245
oliviermartin11c20f42011-09-22 22:53:54 +0000246 return Status;
andrewfish1bfda052011-02-02 22:35:30 +0000247}
248
249//
250// EFI Driver Diagnostics 2 Protocol
251//
252GLOBAL_REMOVE_IF_UNREFERENCED EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gMmcDriverDiagnostics2 = {
253 (EFI_DRIVER_DIAGNOSTICS2_RUN_DIAGNOSTICS) MmcDriverDiagnosticsRunDiagnostics,
254 "en"
255};