]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c
UefiCpuPkg SecCore: Fix operands of different size in bitwise operation
[mirror_edk2.git] / MdeModulePkg / Bus / Ufs / UfsPassThruDxe / UfsPassThruHci.c
CommitLineData
0591696e
FT
1/** @file\r
2 UfsPassThruDxe driver is used to produce EFI_EXT_SCSI_PASS_THRU protocol interface\r
3 for upper layer application to execute UFS-supported SCSI cmds.\r
4\r
16f69227 5 Copyright (c) 2014 - 2017, Intel Corporation. All rights reserved.<BR>\r
0591696e
FT
6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php.\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "UfsPassThru.h"\r
17\r
095f0779
FT
18/**\r
19 Read 32bits data from specified UFS MMIO register.\r
20\r
21 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
22 @param[in] Offset The offset within the UFS Host Controller MMIO space to start\r
23 the memory operation.\r
24 @param[out] Value The data buffer to store.\r
25\r
26 @retval EFI_TIMEOUT The operation is time out.\r
27 @retval EFI_SUCCESS The operation succeeds.\r
28 @retval Others The operation fails.\r
29\r
30**/\r
31EFI_STATUS\r
32UfsMmioRead32 (\r
33 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
34 IN UINTN Offset,\r
35 OUT UINT32 *Value\r
36 )\r
37{\r
38 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
39 EFI_STATUS Status;\r
40\r
41 UfsHc = Private->UfsHostController;\r
42\r
43 Status = UfsHc->Read (UfsHc, EfiUfsHcWidthUint32, Offset, 1, Value);\r
44\r
45 return Status;\r
46}\r
47\r
48/**\r
49 Write 32bits data to specified UFS MMIO register.\r
50\r
51 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
52 @param[in] Offset The offset within the UFS Host Controller MMIO space to start\r
53 the memory operation.\r
54 @param[in] Value The data to write.\r
55\r
56 @retval EFI_TIMEOUT The operation is time out.\r
57 @retval EFI_SUCCESS The operation succeeds.\r
58 @retval Others The operation fails.\r
59\r
60**/\r
61EFI_STATUS\r
62UfsMmioWrite32 (\r
63 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
64 IN UINTN Offset,\r
65 IN UINT32 Value\r
66 )\r
67{\r
68 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
69 EFI_STATUS Status;\r
70\r
71 UfsHc = Private->UfsHostController;\r
72\r
73 Status = UfsHc->Write (UfsHc, EfiUfsHcWidthUint32, Offset, 1, &Value);\r
74\r
75 return Status;\r
76}\r
77\r
0591696e
FT
78/**\r
79 Wait for the value of the specified system memory set to the test value.\r
80\r
095f0779
FT
81 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
82 @param[in] Offset The offset within the UFS Host Controller MMIO space to start\r
83 the memory operation.\r
84 @param[in] MaskValue The mask value of memory.\r
85 @param[in] TestValue The test value of memory.\r
86 @param[in] Timeout The time out value for wait memory set, uses 100ns as a unit.\r
0591696e
FT
87\r
88 @retval EFI_TIMEOUT The system memory setting is time out.\r
89 @retval EFI_SUCCESS The system memory is correct set.\r
095f0779 90 @retval Others The operation fails.\r
0591696e
FT
91\r
92**/\r
93EFI_STATUS\r
0591696e 94UfsWaitMemSet (\r
095f0779
FT
95 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
96 IN UINTN Offset,\r
97 IN UINT32 MaskValue,\r
98 IN UINT32 TestValue,\r
99 IN UINT64 Timeout\r
0591696e
FT
100 )\r
101{\r
102 UINT32 Value;\r
103 UINT64 Delay;\r
104 BOOLEAN InfiniteWait;\r
095f0779 105 EFI_STATUS Status;\r
0591696e
FT
106\r
107 if (Timeout == 0) {\r
108 InfiniteWait = TRUE;\r
109 } else {\r
110 InfiniteWait = FALSE;\r
111 }\r
112\r
113 Delay = DivU64x32 (Timeout, 10) + 1;\r
114\r
115 do {\r
116 //\r
117 // Access PCI MMIO space to see if the value is the tested one.\r
118 //\r
095f0779
FT
119 Status = UfsMmioRead32 (Private, Offset, &Value);\r
120 if (EFI_ERROR (Status)) {\r
121 return Status;\r
122 }\r
123\r
124 Value &= MaskValue;\r
0591696e
FT
125\r
126 if (Value == TestValue) {\r
127 return EFI_SUCCESS;\r
128 }\r
129\r
130 //\r
131 // Stall for 1 microseconds.\r
132 //\r
133 MicroSecondDelay (1);\r
134\r
135 Delay--;\r
136\r
137 } while (InfiniteWait || (Delay > 0));\r
138\r
139 return EFI_TIMEOUT;\r
140}\r
141\r
142/**\r
143 Dump UIC command execution result for debugging.\r
144\r
145 @param[in] UicOpcode The executed UIC opcode.\r
146 @param[in] Result The result to be parsed.\r
147\r
148**/\r
149VOID\r
150DumpUicCmdExecResult (\r
151 IN UINT8 UicOpcode,\r
152 IN UINT8 Result\r
153 )\r
154{\r
155 if (UicOpcode <= UfsUicDmePeerSet) {\r
156 switch (Result) {\r
157 case 0x00:\r
158 break;\r
159 case 0x01:\r
edd94e74 160 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE\n"));\r
0591696e
FT
161 break;\r
162 case 0x02:\r
edd94e74 163 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - INVALID_MIB_ATTRIBUTE_VALUE\n"));\r
0591696e
FT
164 break;\r
165 case 0x03:\r
edd94e74 166 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - READ_ONLY_MIB_ATTRIBUTE\n"));\r
0591696e
FT
167 break;\r
168 case 0x04:\r
edd94e74 169 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - WRITE_ONLY_MIB_ATTRIBUTE\n"));\r
0591696e
FT
170 break;\r
171 case 0x05:\r
edd94e74 172 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BAD_INDEX\n"));\r
0591696e
FT
173 break;\r
174 case 0x06:\r
edd94e74 175 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - LOCKED_MIB_ATTRIBUTE\n"));\r
0591696e
FT
176 break;\r
177 case 0x07:\r
edd94e74 178 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BAD_TEST_FEATURE_INDEX\n"));\r
0591696e
FT
179 break;\r
180 case 0x08:\r
edd94e74 181 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - PEER_COMMUNICATION_FAILURE\n"));\r
0591696e
FT
182 break; \r
183 case 0x09:\r
edd94e74 184 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - BUSY\n"));\r
0591696e
FT
185 break;\r
186 case 0x0A:\r
edd94e74 187 DEBUG ((DEBUG_VERBOSE, "UIC configuration command fails - DME_FAILURE\n"));\r
0591696e
FT
188 break; \r
189 default :\r
190 ASSERT (FALSE);\r
191 break;\r
192 }\r
193 } else {\r
194 switch (Result) {\r
195 case 0x00:\r
196 break;\r
197 case 0x01:\r
edd94e74 198 DEBUG ((DEBUG_VERBOSE, "UIC control command fails - FAILURE\n"));\r
0591696e
FT
199 break; \r
200 default :\r
201 ASSERT (FALSE);\r
202 break;\r
203 }\r
204 }\r
205}\r
206\r
207/**\r
208 Dump QUERY RESPONSE UPIU result for debugging.\r
209\r
210 @param[in] Result The result to be parsed.\r
211\r
212**/\r
213VOID\r
214DumpQueryResponseResult (\r
215 IN UINT8 Result\r
216 )\r
217{\r
218 switch (Result) {\r
219 case 0xF6:\r
edd94e74 220 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Not Readable\n"));\r
0591696e
FT
221 break;\r
222 case 0xF7:\r
edd94e74 223 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Not Writeable\n"));\r
0591696e
FT
224 break;\r
225 case 0xF8:\r
edd94e74 226 DEBUG ((DEBUG_VERBOSE, "Query Response with Parameter Already Written\n"));\r
0591696e
FT
227 break;\r
228 case 0xF9:\r
edd94e74 229 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Length\n"));\r
0591696e
FT
230 break;\r
231 case 0xFA:\r
edd94e74 232 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Value\n"));\r
0591696e
FT
233 break;\r
234 case 0xFB:\r
edd94e74 235 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Selector\n"));\r
0591696e
FT
236 break;\r
237 case 0xFC:\r
edd94e74 238 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Index\n"));\r
0591696e
FT
239 break;\r
240 case 0xFD:\r
edd94e74 241 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Idn\n"));\r
0591696e
FT
242 break;\r
243 case 0xFE:\r
edd94e74 244 DEBUG ((DEBUG_VERBOSE, "Query Response with Invalid Opcode\n"));\r
0591696e
FT
245 break; \r
246 case 0xFF:\r
edd94e74 247 DEBUG ((DEBUG_VERBOSE, "Query Response with General Failure\n"));\r
0591696e
FT
248 break;\r
249 default :\r
250 ASSERT (FALSE);\r
251 break;\r
252 }\r
253}\r
254\r
255/**\r
256 Swap little endian to big endian.\r
257\r
258 @param[in, out] Buffer The data buffer. In input, it contains little endian data.\r
259 In output, it will become big endian.\r
260 @param[in] BufferSize The length of converted data.\r
261\r
262**/\r
263VOID\r
264SwapLittleEndianToBigEndian (\r
265 IN OUT UINT8 *Buffer,\r
266 IN UINT32 BufferSize\r
267 )\r
268{\r
269 UINT32 Index;\r
270 UINT8 Temp;\r
271 UINT32 SwapCount;\r
272\r
273 SwapCount = BufferSize / 2;\r
274 for (Index = 0; Index < SwapCount; Index++) {\r
275 Temp = Buffer[Index];\r
276 Buffer[Index] = Buffer[BufferSize - 1 - Index];\r
277 Buffer[BufferSize - 1 - Index] = Temp;\r
278 }\r
279}\r
280\r
281/**\r
282 Fill TSF field of QUERY REQUEST UPIU.\r
283\r
284 @param[in, out] TsfBase The base address of TSF field of QUERY REQUEST UPIU.\r
285 @param[in] Opcode The opcode of request.\r
286 @param[in] DescId The descriptor ID of request.\r
287 @param[in] Index The index of request.\r
288 @param[in] Selector The selector of request.\r
289 @param[in] Length The length of transferred data. The maximum is 4.\r
290 @param[in] Value The value of transferred data.\r
291\r
292**/\r
293VOID\r
294UfsFillTsfOfQueryReqUpiu (\r
295 IN OUT UTP_UPIU_TSF *TsfBase,\r
296 IN UINT8 Opcode,\r
297 IN UINT8 DescId OPTIONAL,\r
298 IN UINT8 Index OPTIONAL,\r
299 IN UINT8 Selector OPTIONAL,\r
300 IN UINT16 Length OPTIONAL,\r
301 IN UINT32 Value OPTIONAL\r
302 )\r
303{\r
304 ASSERT (TsfBase != NULL);\r
305 ASSERT (Opcode <= UtpQueryFuncOpcodeTogFlag);\r
306\r
307 TsfBase->Opcode = Opcode;\r
308 if (Opcode != UtpQueryFuncOpcodeNop) {\r
309 TsfBase->DescId = DescId;\r
310 TsfBase->Index = Index;\r
311 TsfBase->Selector = Selector;\r
312\r
313 if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {\r
314 SwapLittleEndianToBigEndian ((UINT8*)&Length, sizeof (Length));\r
315 TsfBase->Length = Length;\r
316 }\r
317 \r
318 if (Opcode == UtpQueryFuncOpcodeWrAttr) {\r
319 SwapLittleEndianToBigEndian ((UINT8*)&Value, sizeof (Value));\r
320 TsfBase->Value = Value;\r
321 }\r
322 }\r
323}\r
324\r
325/**\r
326 Initialize COMMAND UPIU.\r
327\r
328 @param[in, out] Command The base address of COMMAND UPIU.\r
329 @param[in] Lun The Lun on which the SCSI command is executed.\r
330 @param[in] TaskTag The task tag of request.\r
331 @param[in] Cdb The cdb buffer containing SCSI command.\r
332 @param[in] CdbLength The cdb length.\r
333 @param[in] DataDirection The direction of data transfer.\r
334 @param[in] ExpDataTranLen The expected transfer data length.\r
335\r
336 @retval EFI_SUCCESS The initialization succeed.\r
337\r
338**/\r
339EFI_STATUS\r
340UfsInitCommandUpiu (\r
341 IN OUT UTP_COMMAND_UPIU *Command,\r
342 IN UINT8 Lun,\r
343 IN UINT8 TaskTag,\r
344 IN UINT8 *Cdb,\r
345 IN UINT8 CdbLength,\r
346 IN UFS_DATA_DIRECTION DataDirection,\r
347 IN UINT32 ExpDataTranLen\r
348 )\r
349{\r
350 UINT8 Flags;\r
351\r
352 ASSERT ((Command != NULL) && (Cdb != NULL));\r
353\r
354 //\r
355 // Task attribute is hard-coded to Ordered.\r
356 //\r
357 if (DataDirection == UfsDataIn) {\r
358 Flags = BIT0 | BIT6;\r
359 } else if (DataDirection == UfsDataOut) {\r
360 Flags = BIT0 | BIT5;\r
361 } else {\r
362 Flags = BIT0;\r
363 }\r
364\r
365 //\r
366 // Fill UTP COMMAND UPIU associated fields.\r
367 //\r
368 Command->TransCode = 0x01;\r
369 Command->Flags = Flags;\r
370 Command->Lun = Lun;\r
371 Command->TaskTag = TaskTag;\r
372 Command->CmdSet = 0x00;\r
373 SwapLittleEndianToBigEndian ((UINT8*)&ExpDataTranLen, sizeof (ExpDataTranLen));\r
374 Command->ExpDataTranLen = ExpDataTranLen;\r
375\r
376 CopyMem (Command->Cdb, Cdb, CdbLength);\r
377\r
378 return EFI_SUCCESS;\r
379}\r
380\r
381/**\r
382 Initialize UTP PRDT for data transfer.\r
383\r
384 @param[in] Prdt The base address of PRDT.\r
385 @param[in] Buffer The buffer to be read or written.\r
386 @param[in] BufferSize The data size to be read or written.\r
387\r
388 @retval EFI_SUCCESS The initialization succeed.\r
389\r
390**/\r
391EFI_STATUS\r
392UfsInitUtpPrdt (\r
393 IN UTP_TR_PRD *Prdt,\r
394 IN VOID *Buffer,\r
395 IN UINT32 BufferSize\r
396 )\r
397{\r
398 UINT32 PrdtIndex;\r
399 UINT32 RemainingLen;\r
400 UINT8 *Remaining;\r
401 UINTN PrdtNumber;\r
402\r
d945390d
FT
403 if ((BufferSize & (BIT0 | BIT1)) != 0) {\r
404 BufferSize &= ~(BIT0 | BIT1);\r
edd94e74 405 DEBUG ((DEBUG_WARN, "UfsInitUtpPrdt: The BufferSize [%d] is not dword-aligned!\n", BufferSize));\r
d945390d
FT
406 }\r
407\r
0591696e
FT
408 if (BufferSize == 0) {\r
409 return EFI_SUCCESS;\r
410 }\r
411\r
412 ASSERT (((UINTN)Buffer & (BIT0 | BIT1)) == 0);\r
413\r
414 RemainingLen = BufferSize;\r
415 Remaining = Buffer;\r
416 PrdtNumber = (UINTN)DivU64x32 ((UINT64)BufferSize + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);\r
417\r
418 for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {\r
419 if (RemainingLen < UFS_MAX_DATA_LEN_PER_PRD) {\r
420 Prdt[PrdtIndex].DbCount = (UINT32)RemainingLen - 1;\r
421 } else {\r
422 Prdt[PrdtIndex].DbCount = UFS_MAX_DATA_LEN_PER_PRD - 1;\r
423 }\r
424\r
425 Prdt[PrdtIndex].DbAddr = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 2);\r
426 Prdt[PrdtIndex].DbAddrU = (UINT32)RShiftU64 ((UINT64)(UINTN)Remaining, 32);\r
427 RemainingLen -= UFS_MAX_DATA_LEN_PER_PRD;\r
428 Remaining += UFS_MAX_DATA_LEN_PER_PRD;\r
429 }\r
430\r
431 return EFI_SUCCESS;\r
432}\r
433\r
434/**\r
435 Initialize QUERY REQUEST UPIU.\r
436\r
437 @param[in, out] QueryReq The base address of QUERY REQUEST UPIU.\r
438 @param[in] TaskTag The task tag of request.\r
439 @param[in] Opcode The opcode of request.\r
440 @param[in] DescId The descriptor ID of request.\r
441 @param[in] Index The index of request.\r
442 @param[in] Selector The selector of request.\r
443 @param[in] DataSize The data size to be read or written.\r
444 @param[in] Data The buffer to be read or written.\r
445\r
446 @retval EFI_SUCCESS The initialization succeed.\r
447\r
448**/\r
449EFI_STATUS\r
450UfsInitQueryRequestUpiu (\r
451 IN OUT UTP_QUERY_REQ_UPIU *QueryReq,\r
452 IN UINT8 TaskTag,\r
453 IN UINT8 Opcode,\r
454 IN UINT8 DescId,\r
455 IN UINT8 Index,\r
456 IN UINT8 Selector,\r
457 IN UINTN DataSize OPTIONAL,\r
458 IN UINT8 *Data OPTIONAL\r
459 )\r
460{\r
461 ASSERT (QueryReq != NULL);\r
462\r
463 QueryReq->TransCode = 0x16;\r
464 QueryReq->TaskTag = TaskTag;\r
465 if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeRdFlag) || (Opcode == UtpQueryFuncOpcodeRdAttr)) {\r
466 QueryReq->QueryFunc = QUERY_FUNC_STD_READ_REQ;\r
467 } else {\r
468 QueryReq->QueryFunc = QUERY_FUNC_STD_WRITE_REQ;\r
469 }\r
470\r
471 if (Opcode == UtpQueryFuncOpcodeWrAttr) {\r
472 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, *(UINT32*)Data);\r
473 } else if ((Opcode == UtpQueryFuncOpcodeRdDesc) || (Opcode == UtpQueryFuncOpcodeWrDesc)) {\r
474 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, (UINT16)DataSize, 0);\r
475 } else {\r
476 UfsFillTsfOfQueryReqUpiu (&QueryReq->Tsf, Opcode, DescId, Index, Selector, 0, 0);\r
477 }\r
478\r
479 if (Opcode == UtpQueryFuncOpcodeWrDesc) {\r
480 CopyMem (QueryReq + 1, Data, DataSize);\r
481 }\r
482\r
483 return EFI_SUCCESS;\r
484}\r
485\r
486/**\r
487 Allocate COMMAND/RESPONSE UPIU for filling UTP TRD's command descriptor field.\r
488\r
489 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
490 @param[in] Lun The Lun on which the SCSI command is executed.\r
491 @param[in] Packet The pointer to the EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.\r
492 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.\r
493 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.\r
494 @param[out] CmdDescMapping A resulting value to pass to Unmap().\r
495\r
496 @retval EFI_SUCCESS The creation succeed.\r
497 @retval EFI_DEVICE_ERROR The creation failed.\r
498 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.\r
499\r
500**/\r
501EFI_STATUS\r
502UfsCreateScsiCommandDesc (\r
503 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
504 IN UINT8 Lun,\r
505 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,\r
506 IN UTP_TRD *Trd,\r
507 OUT VOID **CmdDescHost,\r
508 OUT VOID **CmdDescMapping\r
509 )\r
510{\r
511 UINTN TotalLen;\r
512 UINTN PrdtNumber;\r
513 UTP_COMMAND_UPIU *CommandUpiu;\r
514 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
515 EFI_STATUS Status;\r
516 UINT32 DataLen;\r
517 UFS_DATA_DIRECTION DataDirection;\r
518\r
519 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));\r
520\r
521 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
522 DataLen = Packet->InTransferLength;\r
523 DataDirection = UfsDataIn;\r
524 } else {\r
525 DataLen = Packet->OutTransferLength;\r
526 DataDirection = UfsDataOut;\r
527 }\r
528\r
529 if (DataLen == 0) {\r
530 DataDirection = UfsNoData;\r
531 }\r
532\r
533 PrdtNumber = (UINTN)DivU64x32 ((UINT64)DataLen + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);\r
534\r
535 TotalLen = ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)) + PrdtNumber * sizeof (UTP_TR_PRD);\r
536\r
537 Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);\r
538 if (EFI_ERROR (Status)) {\r
539 return Status;\r
540 }\r
541\r
542 CommandUpiu = (UTP_COMMAND_UPIU*)*CmdDescHost;\r
543\r
544 UfsInitCommandUpiu (CommandUpiu, Lun, Private->TaskTag++, Packet->Cdb, Packet->CdbLength, DataDirection, DataLen);\r
545\r
546 //\r
547 // Fill UTP_TRD associated fields\r
548 // NOTE: Some UFS host controllers request the Response UPIU and the Physical Region Description Table\r
549 // *MUST* be located at a 64-bit aligned boundary.\r
550 //\r
551 Trd->Int = UFS_INTERRUPT_COMMAND;\r
552 Trd->Dd = DataDirection;\r
553 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;\r
86bd34ca 554 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;\r
0591696e
FT
555 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);\r
556 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);\r
557 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)), sizeof (UINT32));\r
558 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)), sizeof (UINT32));\r
559 Trd->PrdtL = (UINT16)PrdtNumber;\r
560 Trd->PrdtO = (UINT16)DivU64x32 ((UINT64)(ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))), sizeof (UINT32));\r
561 return EFI_SUCCESS;\r
562}\r
563\r
564/**\r
565 Allocate QUERY REQUEST/QUERY RESPONSE UPIU for filling UTP TRD's command descriptor field.\r
566\r
567 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
568 @param[in] Packet The pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET data structure.\r
569 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.\r
570 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.\r
571 @param[out] CmdDescMapping A resulting value to pass to Unmap().\r
572\r
573 @retval EFI_SUCCESS The creation succeed.\r
574 @retval EFI_DEVICE_ERROR The creation failed.\r
575 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.\r
576 @retval EFI_INVALID_PARAMETER The parameter passed in is invalid.\r
577\r
578**/\r
579EFI_STATUS\r
580UfsCreateDMCommandDesc (\r
581 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
582 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,\r
583 IN UTP_TRD *Trd,\r
584 OUT VOID **CmdDescHost,\r
585 OUT VOID **CmdDescMapping\r
586 )\r
587{\r
588 UINTN TotalLen;\r
589 UTP_QUERY_REQ_UPIU *QueryReqUpiu;\r
590 UINT8 Opcode;\r
591 UINT32 DataSize;\r
592 UINT8 *Data;\r
593 UINT8 DataDirection;\r
594 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
595 EFI_STATUS Status;\r
596\r
597 ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));\r
598\r
599 Opcode = Packet->Opcode;\r
600 if ((Opcode > UtpQueryFuncOpcodeTogFlag) || (Opcode == UtpQueryFuncOpcodeNop)) {\r
601 return EFI_INVALID_PARAMETER;\r
602 }\r
603\r
604 DataDirection = Packet->DataDirection;\r
95ad8f7f
HW
605 DataSize = Packet->TransferLength;\r
606 Data = Packet->DataBuffer;\r
0591696e
FT
607\r
608 if ((Opcode == UtpQueryFuncOpcodeWrDesc) || (Opcode == UtpQueryFuncOpcodeRdDesc)) {\r
95ad8f7f
HW
609 if (DataSize == 0 || Data == NULL) {\r
610 return EFI_INVALID_PARAMETER;\r
611 }\r
0591696e
FT
612 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize);\r
613 } else {\r
614 TotalLen = ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU));\r
615 }\r
616\r
617 Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);\r
618 if (EFI_ERROR (Status)) {\r
619 return Status;\r
620 }\r
621\r
622 //\r
623 // Initialize UTP QUERY REQUEST UPIU\r
624 //\r
625 QueryReqUpiu = (UTP_QUERY_REQ_UPIU*)*CmdDescHost;\r
626 ASSERT (QueryReqUpiu != NULL);\r
627 UfsInitQueryRequestUpiu (\r
628 QueryReqUpiu,\r
629 Private->TaskTag++,\r
630 Opcode,\r
631 Packet->DescId,\r
632 Packet->Index,\r
633 Packet->Selector,\r
634 DataSize,\r
635 Data\r
636 );\r
637\r
638 //\r
639 // Fill UTP_TRD associated fields\r
640 // NOTE: Some UFS host controllers request the Query Response UPIU *MUST* be located at a 64-bit aligned boundary.\r
641 //\r
642 Trd->Int = UFS_INTERRUPT_COMMAND;\r
643 Trd->Dd = DataDirection;\r
644 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;\r
86bd34ca 645 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;\r
0591696e
FT
646 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);\r
647 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);\r
648 if (Opcode == UtpQueryFuncOpcodeWrDesc) {\r
649 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)), sizeof (UINT32));\r
16f69227 650 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));\r
0591696e 651 } else {\r
16f69227 652 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_RESP_UPIU)) + ROUNDUP8 (DataSize), sizeof (UINT32));\r
0591696e
FT
653 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_QUERY_REQ_UPIU)), sizeof (UINT32));\r
654 }\r
655\r
656 return EFI_SUCCESS;\r
657}\r
658\r
659/**\r
660 Allocate NOP IN and NOP OUT UPIU for filling UTP TRD's command descriptor field.\r
661\r
662 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
663 @param[in] Trd The pointer to the UTP Transfer Request Descriptor.\r
664 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.\r
665 @param[out] CmdDescMapping A resulting value to pass to Unmap().\r
666\r
667 @retval EFI_SUCCESS The creation succeed.\r
668 @retval EFI_DEVICE_ERROR The creation failed.\r
669 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.\r
670\r
671**/\r
672EFI_STATUS\r
673UfsCreateNopCommandDesc (\r
674 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
675 IN UTP_TRD *Trd,\r
676 OUT VOID **CmdDescHost,\r
677 OUT VOID **CmdDescMapping\r
678 )\r
679{\r
680 UINTN TotalLen;\r
681 UTP_NOP_OUT_UPIU *NopOutUpiu;\r
682 EFI_STATUS Status;\r
683 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
684\r
685 ASSERT ((Private != NULL) && (Trd != NULL));\r
686\r
687 TotalLen = ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)) + ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU));\r
688 Status = UfsAllocateAlignCommonBuffer (Private, TotalLen, CmdDescHost, &CmdDescPhyAddr, CmdDescMapping);\r
689 if (EFI_ERROR (Status)) {\r
690 return Status;\r
691 }\r
692\r
693 NopOutUpiu = (UTP_NOP_OUT_UPIU*)*CmdDescHost;\r
694 ASSERT (NopOutUpiu != NULL);\r
695 NopOutUpiu->TaskTag = Private->TaskTag++;\r
696\r
697 //\r
698 // Fill UTP_TRD associated fields\r
699 // NOTE: Some UFS host controllers request the Nop Out UPIU *MUST* be located at a 64-bit aligned boundary.\r
700 //\r
701 Trd->Int = UFS_INTERRUPT_COMMAND;\r
702 Trd->Dd = 0x00;\r
703 Trd->Ct = UFS_STORAGE_COMMAND_TYPE;\r
86bd34ca 704 Trd->Ocs = UFS_HC_TRD_OCS_INIT_VALUE;\r
0591696e
FT
705 Trd->UcdBa = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 7);\r
706 Trd->UcdBaU = (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32);\r
707 Trd->RuL = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_IN_UPIU)), sizeof (UINT32));\r
708 Trd->RuO = (UINT16)DivU64x32 ((UINT64)ROUNDUP8 (sizeof (UTP_NOP_OUT_UPIU)), sizeof (UINT32));\r
709\r
710 return EFI_SUCCESS;\r
711}\r
712\r
713/**\r
714 Find out available slot in transfer list of a UFS device.\r
715\r
716 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
717 @param[out] Slot The available slot.\r
718\r
719 @retval EFI_SUCCESS The available slot was found successfully.\r
0350b57c 720 @retval EFI_NOT_READY No slot is available at this moment.\r
0591696e
FT
721\r
722**/\r
723EFI_STATUS\r
724UfsFindAvailableSlotInTrl (\r
725 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
726 OUT UINT8 *Slot\r
727 )\r
728{\r
0350b57c
HW
729 UINT8 Nutrs;\r
730 UINT8 Index;\r
731 UINT32 Data;\r
732 EFI_STATUS Status;\r
733\r
0591696e
FT
734 ASSERT ((Private != NULL) && (Slot != NULL));\r
735\r
0350b57c
HW
736 Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Data);\r
737 if (EFI_ERROR (Status)) {\r
738 return Status;\r
739 }\r
0591696e 740\r
0350b57c
HW
741 Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);\r
742\r
743 for (Index = 0; Index < Nutrs; Index++) {\r
744 if ((Data & (BIT0 << Index)) == 0) {\r
745 *Slot = Index;\r
746 return EFI_SUCCESS;\r
747 }\r
748 }\r
749\r
750 return EFI_NOT_READY;\r
0591696e
FT
751}\r
752\r
753/**\r
754 Find out available slot in task management transfer list of a UFS device.\r
755\r
756 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
757 @param[out] Slot The available slot.\r
758\r
759 @retval EFI_SUCCESS The available slot was found successfully.\r
760\r
761**/\r
762EFI_STATUS\r
763UfsFindAvailableSlotInTmrl (\r
764 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
765 OUT UINT8 *Slot\r
766 )\r
767{\r
768 ASSERT ((Private != NULL) && (Slot != NULL));\r
769\r
770 //\r
771 // The simplest algo to always use slot 0.\r
772 // TODO: enhance it to support async transfer with multiple slot.\r
773 //\r
774 *Slot = 0;\r
775\r
776 return EFI_SUCCESS;\r
777}\r
778\r
779/**\r
780 Start specified slot in transfer list of a UFS device.\r
781\r
782 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
783 @param[in] Slot The slot to be started.\r
784\r
785**/\r
095f0779 786EFI_STATUS\r
0591696e
FT
787UfsStartExecCmd (\r
788 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
789 IN UINT8 Slot\r
790 ) \r
791{\r
0591696e 792 UINT32 Data;\r
095f0779 793 EFI_STATUS Status;\r
0591696e 794\r
095f0779
FT
795 Status = UfsMmioRead32 (Private, UFS_HC_UTRLRSR_OFFSET, &Data);\r
796 if (EFI_ERROR (Status)) {\r
797 return Status;\r
798 }\r
0591696e 799\r
0591696e 800 if ((Data & UFS_HC_UTRLRSR) != UFS_HC_UTRLRSR) {\r
095f0779
FT
801 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, UFS_HC_UTRLRSR);\r
802 if (EFI_ERROR (Status)) {\r
803 return Status;\r
804 }\r
805 }\r
806\r
807 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << Slot);\r
808 if (EFI_ERROR (Status)) {\r
809 return Status;\r
0591696e
FT
810 }\r
811\r
095f0779 812 return EFI_SUCCESS;\r
0591696e
FT
813}\r
814\r
815/**\r
816 Stop specified slot in transfer list of a UFS device.\r
817\r
818 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
819 @param[in] Slot The slot to be stop.\r
820\r
821**/\r
095f0779 822EFI_STATUS\r
0591696e
FT
823UfsStopExecCmd (\r
824 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
825 IN UINT8 Slot\r
826 ) \r
827{\r
0591696e 828 UINT32 Data;\r
095f0779 829 EFI_STATUS Status;\r
0591696e 830\r
095f0779
FT
831 Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Data);\r
832 if (EFI_ERROR (Status)) {\r
833 return Status;\r
834 }\r
0591696e 835\r
0591696e 836 if ((Data & (BIT0 << Slot)) != 0) {\r
095f0779
FT
837 Status = UfsMmioRead32 (Private, UFS_HC_UTRLCLR_OFFSET, &Data);\r
838 if (EFI_ERROR (Status)) {\r
839 return Status;\r
840 }\r
841\r
842 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLCLR_OFFSET, Data & ~(BIT0 << Slot));\r
843 if (EFI_ERROR (Status)) {\r
844 return Status;\r
845 }\r
0591696e 846 }\r
095f0779
FT
847\r
848 return EFI_SUCCESS;\r
0591696e
FT
849}\r
850\r
851/**\r
95ad8f7f 852 Extracts return data from query response upiu.\r
0591696e 853\r
95ad8f7f
HW
854 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.\r
855 @param[in] QueryResp Pointer to the query response.\r
0591696e 856\r
95ad8f7f
HW
857 @retval EFI_INVALID_PARAMETER Packet or QueryResp are empty or opcode is invalid.\r
858 @retval EFI_SUCCESS Data extracted.\r
0591696e
FT
859\r
860**/\r
861EFI_STATUS\r
95ad8f7f
HW
862UfsGetReturnDataFromQueryResponse (\r
863 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,\r
864 IN UTP_QUERY_RESP_UPIU *QueryResp\r
0591696e
FT
865 )\r
866{\r
95ad8f7f
HW
867 UINT16 ReturnDataSize;\r
868 UINT32 ReturnData;\r
0591696e 869\r
95ad8f7f
HW
870 if (Packet == NULL || QueryResp == NULL) {\r
871 return EFI_INVALID_PARAMETER;\r
872 }\r
0591696e 873\r
95ad8f7f
HW
874 switch (Packet->Opcode) {\r
875 case UtpQueryFuncOpcodeRdDesc:\r
876 ReturnDataSize = QueryResp->Tsf.Length;\r
877 SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));\r
878 CopyMem (Packet->DataBuffer, (QueryResp + 1), ReturnDataSize);\r
879 Packet->TransferLength = ReturnDataSize;\r
880 break;\r
881 case UtpQueryFuncOpcodeWrDesc:\r
882 ReturnDataSize = QueryResp->Tsf.Length;\r
883 SwapLittleEndianToBigEndian ((UINT8*)&ReturnDataSize, sizeof (UINT16));\r
884 Packet->TransferLength = ReturnDataSize;\r
885 break;\r
886 case UtpQueryFuncOpcodeRdFlag:\r
887 case UtpQueryFuncOpcodeSetFlag:\r
888 case UtpQueryFuncOpcodeClrFlag:\r
889 case UtpQueryFuncOpcodeTogFlag:\r
890 CopyMem (Packet->DataBuffer, &QueryResp->Tsf.Value, sizeof (UINT8));\r
891 break;\r
892 case UtpQueryFuncOpcodeRdAttr:\r
893 case UtpQueryFuncOpcodeWrAttr:\r
894 ReturnData = QueryResp->Tsf.Value;\r
895 SwapLittleEndianToBigEndian ((UINT8*) &ReturnData, sizeof (UINT32));\r
896 CopyMem (Packet->DataBuffer, &ReturnData, sizeof (UINT32));\r
897 break;\r
898 default:\r
899 return EFI_INVALID_PARAMETER;\r
0591696e 900 }\r
95ad8f7f
HW
901\r
902 return EFI_SUCCESS;\r
903}\r
904\r
905/**\r
906 Creates Transfer Request descriptor and sends Query Request to the device.\r
907\r
908 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.\r
909 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.\r
910\r
911 @retval EFI_SUCCESS The device descriptor was read/written successfully.\r
912 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.\r
913 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.\r
914\r
915**/\r
916EFI_STATUS\r
917UfsSendDmRequestRetry (\r
918 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
919 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet\r
920 )\r
921{\r
922 UINT8 Slot;\r
923 UTP_TRD *Trd;\r
924 VOID *CmdDescHost;\r
925 VOID *CmdDescMapping;\r
926 UINT32 CmdDescSize;\r
927 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
928 UTP_QUERY_RESP_UPIU *QueryResp;\r
929 EFI_STATUS Status;\r
0591696e
FT
930\r
931 //\r
932 // Find out which slot of transfer request list is available.\r
933 //\r
934 Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
935 if (EFI_ERROR (Status)) {\r
936 return Status;\r
937 }\r
938 \r
939 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
940 //\r
941 // Fill transfer request descriptor to this slot.\r
942 //\r
95ad8f7f 943 Status = UfsCreateDMCommandDesc (Private, Packet, Trd, &CmdDescHost, &CmdDescMapping);\r
0591696e 944 if (EFI_ERROR (Status)) {\r
95ad8f7f 945 DEBUG ((DEBUG_ERROR, "Failed to create DM command descriptor\n"));\r
0591696e
FT
946 return Status;\r
947 }\r
948\r
0591696e
FT
949 UfsHc = Private->UfsHostController;\r
950 QueryResp = (UTP_QUERY_RESP_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));\r
951 ASSERT (QueryResp != NULL);\r
952 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
953\r
954 //\r
955 // Start to execute the transfer request.\r
956 //\r
957 UfsStartExecCmd (Private, Slot);\r
958\r
959 //\r
960 // Wait for the completion of the transfer request.\r
95ad8f7f
HW
961 //\r
962 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0, 0, Packet->Timeout);\r
0591696e
FT
963 if (EFI_ERROR (Status)) {\r
964 goto Exit;\r
965 }\r
966\r
95ad8f7f
HW
967 if (Trd->Ocs != 0 || QueryResp->QueryResp != UfsUtpQueryResponseSuccess) {\r
968 DEBUG ((DEBUG_ERROR, "Failed to send query request, OCS = %X, QueryResp = %X\n", Trd->Ocs, QueryResp->QueryResp));\r
0591696e
FT
969 DumpQueryResponseResult (QueryResp->QueryResp);\r
970 Status = EFI_DEVICE_ERROR;\r
971 goto Exit;\r
972 }\r
973\r
95ad8f7f
HW
974 Status = UfsGetReturnDataFromQueryResponse (Packet, QueryResp);\r
975 if (EFI_ERROR (Status)) {\r
976 DEBUG ((DEBUG_ERROR, "Failed to get return data from query response\n"));\r
977 goto Exit;\r
0591696e
FT
978 }\r
979\r
980Exit:\r
981 UfsHc->Flush (UfsHc);\r
982\r
983 UfsStopExecCmd (Private, Slot);\r
984\r
985 if (CmdDescMapping != NULL) {\r
986 UfsHc->Unmap (UfsHc, CmdDescMapping);\r
987 }\r
988 if (CmdDescHost != NULL) {\r
989 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);\r
990 }\r
991\r
992 return Status;\r
993}\r
994\r
95ad8f7f
HW
995/**\r
996 Sends Query Request to the device. Query is sent until device responds correctly or counter runs out.\r
997\r
998 @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA.\r
999 @param[in] Packet Pointer to the UFS_DEVICE_MANAGEMENT_PACKET.\r
1000\r
1001 @retval EFI_SUCCESS The device responded correctly to the Query request.\r
1002 @retval EFI_DEVICE_ERROR A device error occurred while waiting for the response from the device.\r
1003 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of the operation.\r
1004\r
1005**/\r
1006EFI_STATUS\r
1007UfsSendDmRequest (\r
1008 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1009 IN UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet\r
1010 )\r
1011{\r
1012 EFI_STATUS Status;\r
1013 UINT8 Retry;\r
1014\r
1015 Status = EFI_SUCCESS;\r
1016\r
1017 for (Retry = 0; Retry < 5; Retry ++) {\r
1018 Status = UfsSendDmRequestRetry (Private, Packet);\r
1019 if (!EFI_ERROR (Status)) {\r
1020 return EFI_SUCCESS;\r
1021 }\r
1022 }\r
1023\r
1024 DEBUG ((DEBUG_ERROR, "Failed to get response from the device after %d retries\n", Retry));\r
1025 return Status;\r
1026}\r
1027\r
1028/**\r
1029 Read or write specified device descriptor of a UFS device.\r
1030\r
1031 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1032 @param[in] Read The boolean variable to show r/w direction.\r
1033 @param[in] DescId The ID of device descriptor.\r
1034 @param[in] Index The Index of device descriptor.\r
1035 @param[in] Selector The Selector of device descriptor.\r
1036 @param[in, out] Descriptor The buffer of device descriptor to be read or written.\r
1037 @param[in] DescSize The size of device descriptor buffer.\r
1038\r
1039 @retval EFI_SUCCESS The device descriptor was read/written successfully.\r
1040 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.\r
1041 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.\r
1042\r
1043**/\r
1044EFI_STATUS\r
1045UfsRwDeviceDesc (\r
1046 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1047 IN BOOLEAN Read,\r
1048 IN UINT8 DescId,\r
1049 IN UINT8 Index,\r
1050 IN UINT8 Selector,\r
1051 IN OUT VOID *Descriptor,\r
1052 IN UINT32 DescSize\r
1053 )\r
1054{\r
1055 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
1056\r
1057 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
1058\r
1059 if (Read) {\r
1060 Packet.DataDirection = UfsDataIn;\r
1061 Packet.Opcode = UtpQueryFuncOpcodeRdDesc;\r
1062 } else {\r
1063 Packet.DataDirection = UfsDataOut;\r
1064 Packet.Opcode = UtpQueryFuncOpcodeWrDesc;\r
1065 }\r
1066 Packet.DataBuffer = Descriptor;\r
1067 Packet.TransferLength = DescSize;\r
1068 Packet.DescId = DescId;\r
1069 Packet.Index = Index;\r
1070 Packet.Selector = Selector;\r
1071 Packet.Timeout = UFS_TIMEOUT;\r
1072\r
1073 return UfsSendDmRequest (Private, &Packet);\r
1074}\r
1075\r
0591696e
FT
1076/**\r
1077 Read or write specified attribute of a UFS device.\r
1078\r
1079 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1080 @param[in] Read The boolean variable to show r/w direction.\r
1081 @param[in] AttrId The ID of Attribute.\r
1082 @param[in] Index The Index of Attribute.\r
1083 @param[in] Selector The Selector of Attribute.\r
1084 @param[in, out] Attributes The value of Attribute to be read or written.\r
1085\r
1086 @retval EFI_SUCCESS The Attribute was read/written successfully.\r
1087 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the Attribute.\r
1088 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the Attribute.\r
1089\r
1090**/\r
1091EFI_STATUS\r
1092UfsRwAttributes (\r
1093 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1094 IN BOOLEAN Read,\r
1095 IN UINT8 AttrId,\r
1096 IN UINT8 Index,\r
1097 IN UINT8 Selector,\r
1098 IN OUT UINT32 *Attributes\r
1099 )\r
1100{\r
0591696e 1101 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
0591696e
FT
1102\r
1103 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
1104\r
1105 if (Read) {\r
1106 Packet.DataDirection = UfsDataIn;\r
1107 Packet.Opcode = UtpQueryFuncOpcodeRdAttr;\r
1108 } else {\r
1109 Packet.DataDirection = UfsDataOut;\r
1110 Packet.Opcode = UtpQueryFuncOpcodeWrAttr;\r
1111 }\r
95ad8f7f 1112 Packet.DataBuffer = Attributes;\r
0591696e
FT
1113 Packet.DescId = AttrId;\r
1114 Packet.Index = Index;\r
1115 Packet.Selector = Selector;\r
1116 Packet.Timeout = UFS_TIMEOUT;\r
1117\r
95ad8f7f 1118 return UfsSendDmRequest (Private, &Packet);\r
0591696e
FT
1119}\r
1120\r
1121/**\r
1122 Read or write specified flag of a UFS device.\r
1123\r
1124 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1125 @param[in] Read The boolean variable to show r/w direction.\r
1126 @param[in] FlagId The ID of flag to be read or written.\r
1127 @param[in, out] Value The value to set or clear flag.\r
1128\r
1129 @retval EFI_SUCCESS The flag was read/written successfully.\r
1130 @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the flag.\r
1131 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the flag.\r
1132\r
1133**/\r
1134EFI_STATUS\r
1135UfsRwFlags (\r
1136 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1137 IN BOOLEAN Read,\r
1138 IN UINT8 FlagId,\r
1139 IN OUT UINT8 *Value\r
1140 )\r
1141{\r
0591696e 1142 UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
0591696e
FT
1143\r
1144 if (Value == NULL) {\r
1145 return EFI_INVALID_PARAMETER;\r
1146 }\r
1147\r
1148 ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
1149\r
1150 if (Read) {\r
1151 ASSERT (Value != NULL);\r
1152 Packet.DataDirection = UfsDataIn;\r
1153 Packet.Opcode = UtpQueryFuncOpcodeRdFlag;\r
1154 } else {\r
1155 Packet.DataDirection = UfsDataOut;\r
1156 if (*Value == 1) {\r
1157 Packet.Opcode = UtpQueryFuncOpcodeSetFlag;\r
1158 } else if (*Value == 0) {\r
1159 Packet.Opcode = UtpQueryFuncOpcodeClrFlag;\r
1160 } else {\r
1161 return EFI_INVALID_PARAMETER;\r
1162 }\r
1163 }\r
95ad8f7f 1164 Packet.DataBuffer = Value;\r
0591696e
FT
1165 Packet.DescId = FlagId;\r
1166 Packet.Index = 0;\r
1167 Packet.Selector = 0;\r
1168 Packet.Timeout = UFS_TIMEOUT;\r
1169\r
95ad8f7f 1170 return UfsSendDmRequest (Private, &Packet);\r
0591696e
FT
1171}\r
1172\r
1173/**\r
1174 Set specified flag to 1 on a UFS device.\r
1175\r
1176 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1177 @param[in] FlagId The ID of flag to be set.\r
1178\r
1179 @retval EFI_SUCCESS The flag was set successfully.\r
1180 @retval EFI_DEVICE_ERROR A device error occurred while attempting to set the flag.\r
1181 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of setting the flag.\r
1182\r
1183**/\r
1184EFI_STATUS\r
1185UfsSetFlag (\r
1186 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1187 IN UINT8 FlagId\r
1188 )\r
1189{\r
1190 EFI_STATUS Status;\r
1191 UINT8 Value;\r
1192\r
1193 Value = 1;\r
1194 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);\r
1195\r
1196 return Status;\r
1197}\r
1198\r
1199/**\r
1200 Clear specified flag to 0 on a UFS device.\r
1201\r
1202 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1203 @param[in] FlagId The ID of flag to be cleared.\r
1204\r
1205 @retval EFI_SUCCESS The flag was cleared successfully.\r
1206 @retval EFI_DEVICE_ERROR A device error occurred while attempting to clear the flag.\r
1207 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of clearing the flag.\r
1208\r
1209**/\r
1210EFI_STATUS\r
1211UfsClearFlag (\r
1212 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1213 IN UINT8 FlagId\r
1214 )\r
1215{\r
1216 EFI_STATUS Status;\r
1217 UINT8 Value;\r
1218\r
1219 Value = 0;\r
1220 Status = UfsRwFlags (Private, FALSE, FlagId, &Value);\r
1221\r
1222 return Status;\r
1223}\r
1224\r
1225/**\r
1226 Read specified flag from a UFS device.\r
1227\r
1228 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1229 @param[in] FlagId The ID of flag to be read.\r
1230 @param[out] Value The flag's value.\r
1231\r
1232 @retval EFI_SUCCESS The flag was read successfully.\r
1233 @retval EFI_DEVICE_ERROR A device error occurred while attempting to read the flag.\r
1234 @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of reading the flag.\r
1235\r
1236**/\r
1237EFI_STATUS\r
1238UfsReadFlag (\r
1239 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1240 IN UINT8 FlagId,\r
1241 OUT UINT8 *Value\r
1242 )\r
1243{\r
1244 EFI_STATUS Status;\r
1245\r
1246 Status = UfsRwFlags (Private, TRUE, FlagId, Value);\r
1247\r
1248 return Status;\r
1249}\r
1250\r
1251/**\r
1252 Sends NOP IN cmd to a UFS device for initialization process request.\r
1253 For more details, please refer to UFS 2.0 spec Figure 13.3.\r
1254\r
1255 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1256\r
1257 @retval EFI_SUCCESS The NOP IN command was sent by the host. The NOP OUT response was\r
1258 received successfully.\r
1259 @retval EFI_DEVICE_ERROR A device error occurred while attempting to execute NOP IN command.\r
1260 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.\r
1261 @retval EFI_TIMEOUT A timeout occurred while waiting for the NOP IN command to execute.\r
1262\r
1263**/\r
1264EFI_STATUS\r
1265UfsExecNopCmds (\r
1266 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
1267 )\r
1268{\r
1269 EFI_STATUS Status;\r
1270 UINT8 Slot;\r
1271 UTP_TRD *Trd;\r
1272 UTP_NOP_IN_UPIU *NopInUpiu;\r
1273 UINT32 CmdDescSize;\r
0591696e
FT
1274 VOID *CmdDescHost;\r
1275 VOID *CmdDescMapping;\r
1276 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
1277\r
1278 //\r
1279 // Find out which slot of transfer request list is available.\r
1280 //\r
1281 Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
1282 if (EFI_ERROR (Status)) {\r
1283 return Status;\r
1284 }\r
1285\r
1286 Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;\r
1287 Status = UfsCreateNopCommandDesc (Private, Trd, &CmdDescHost, &CmdDescMapping);\r
1288 if (EFI_ERROR (Status)) {\r
1289 return Status;\r
1290 }\r
1291\r
1292 //\r
1293 // Check the transfer request result.\r
1294 //\r
1295 UfsHc = Private->UfsHostController;\r
1296 NopInUpiu = (UTP_NOP_IN_UPIU*)((UINT8*)CmdDescHost + Trd->RuO * sizeof (UINT32));\r
1297 ASSERT (NopInUpiu != NULL);\r
1298 CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
1299\r
1300 //\r
1301 // Start to execute the transfer request.\r
1302 //\r
1303 UfsStartExecCmd (Private, Slot);\r
1304\r
1305 //\r
1306 // Wait for the completion of the transfer request.\r
1307 // \r
13fca387 1308 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << Slot, 0, UFS_TIMEOUT);\r
0591696e
FT
1309 if (EFI_ERROR (Status)) {\r
1310 goto Exit;\r
1311 }\r
1312\r
1313 if (NopInUpiu->Resp != 0) {\r
1314 Status = EFI_DEVICE_ERROR;\r
1315 } else {\r
1316 Status = EFI_SUCCESS;\r
1317 }\r
1318\r
1319Exit:\r
1320 UfsHc->Flush (UfsHc);\r
1321\r
1322 UfsStopExecCmd (Private, Slot);\r
1323\r
1324 if (CmdDescMapping != NULL) {\r
1325 UfsHc->Unmap (UfsHc, CmdDescMapping);\r
1326 }\r
1327 if (CmdDescHost != NULL) {\r
1328 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (CmdDescSize), CmdDescHost);\r
1329 }\r
1330\r
1331 return Status;\r
1332}\r
1333\r
1334/**\r
1335 Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller.\r
1336\r
1337 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1338 @param[in] Lun The LUN of the UFS device to send the SCSI Request Packet.\r
1339 @param[in, out] Packet A pointer to the SCSI Request Packet to send to a specified Lun of the\r
1340 UFS device.\r
0350b57c
HW
1341 @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking\r
1342 I/O is performed. If Event is NULL, then blocking I/O is performed. If\r
1343 Event is not NULL and non blocking I/O is supported, then\r
1344 nonblocking I/O is performed, and Event will be signaled when the\r
1345 SCSI Request Packet completes.\r
0591696e
FT
1346\r
1347 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For bi-directional\r
1348 commands, InTransferLength bytes were transferred from\r
1349 InDataBuffer. For write and bi-directional commands,\r
1350 OutTransferLength bytes were transferred by\r
1351 OutDataBuffer.\r
1352 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the SCSI Request\r
1353 Packet.\r
1354 @retval EFI_OUT_OF_RESOURCES The resource for transfer is not available.\r
1355 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI Request Packet to execute.\r
1356\r
1357**/\r
1358EFI_STATUS\r
1359UfsExecScsiCmds (\r
1360 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1361 IN UINT8 Lun,\r
0350b57c
HW
1362 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,\r
1363 IN EFI_EVENT Event OPTIONAL\r
0591696e
FT
1364 )\r
1365{\r
1366 EFI_STATUS Status;\r
0591696e
FT
1367 UTP_RESPONSE_UPIU *Response;\r
1368 UINT16 SenseDataLen;\r
1369 UINT32 ResTranCount;\r
0591696e
FT
1370 VOID *DataBuf;\r
1371 EFI_PHYSICAL_ADDRESS DataBufPhyAddr;\r
1372 UINT32 DataLen;\r
1373 UINTN MapLength;\r
1374 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
1375 EDKII_UFS_HOST_CONTROLLER_OPERATION Flag;\r
0591696e 1376 UTP_TR_PRD *PrdtBase;\r
0350b57c
HW
1377 EFI_TPL OldTpl;\r
1378 UFS_PASS_THRU_TRANS_REQ *TransReq;\r
0591696e 1379\r
0350b57c
HW
1380 TransReq = AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ));\r
1381 if (TransReq == NULL) {\r
1382 return EFI_OUT_OF_RESOURCES;\r
1383 }\r
1384\r
1385 TransReq->Signature = UFS_PASS_THRU_TRANS_REQ_SIG;\r
1386 TransReq->TimeoutRemain = Packet->Timeout;\r
0591696e
FT
1387 DataBufPhyAddr = 0;\r
1388 UfsHc = Private->UfsHostController;\r
1389 //\r
1390 // Find out which slot of transfer request list is available.\r
1391 //\r
0350b57c 1392 Status = UfsFindAvailableSlotInTrl (Private, &TransReq->Slot);\r
0591696e
FT
1393 if (EFI_ERROR (Status)) {\r
1394 return Status;\r
1395 }\r
1396\r
0350b57c 1397 TransReq->Trd = ((UTP_TRD*)Private->UtpTrlBase) + TransReq->Slot;\r
0591696e
FT
1398\r
1399 //\r
1400 // Fill transfer request descriptor to this slot.\r
1401 //\r
0350b57c
HW
1402 Status = UfsCreateScsiCommandDesc (\r
1403 Private,\r
1404 Lun,\r
1405 Packet,\r
1406 TransReq->Trd,\r
1407 &TransReq->CmdDescHost,\r
1408 &TransReq->CmdDescMapping\r
1409 );\r
0591696e
FT
1410 if (EFI_ERROR (Status)) {\r
1411 return Status;\r
1412 }\r
1413\r
0350b57c 1414 TransReq->CmdDescSize = TransReq->Trd->PrdtO * sizeof (UINT32) + TransReq->Trd->PrdtL * sizeof (UTP_TR_PRD);\r
0591696e
FT
1415\r
1416 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
1417 DataBuf = Packet->InDataBuffer;\r
1418 DataLen = Packet->InTransferLength;\r
0591696e
FT
1419 Flag = EdkiiUfsHcOperationBusMasterWrite;\r
1420 } else {\r
1421 DataBuf = Packet->OutDataBuffer;\r
1422 DataLen = Packet->OutTransferLength;\r
0591696e
FT
1423 Flag = EdkiiUfsHcOperationBusMasterRead;\r
1424 }\r
1425\r
59ddab7e 1426 if (DataLen != 0) {\r
0591696e
FT
1427 MapLength = DataLen;\r
1428 Status = UfsHc->Map (\r
1429 UfsHc,\r
1430 Flag,\r
1431 DataBuf,\r
1432 &MapLength,\r
1433 &DataBufPhyAddr,\r
0350b57c 1434 &TransReq->DataBufMapping\r
0591696e
FT
1435 );\r
1436\r
1437 if (EFI_ERROR (Status) || (DataLen != MapLength)) {\r
1438 goto Exit1;\r
1439 }\r
1440 }\r
1441 //\r
1442 // Fill PRDT table of Command UPIU for executed SCSI cmd.\r
1443 //\r
0350b57c 1444 PrdtBase = (UTP_TR_PRD*)((UINT8*)TransReq->CmdDescHost + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));\r
0591696e
FT
1445 ASSERT (PrdtBase != NULL);\r
1446 UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)DataBufPhyAddr, DataLen);\r
1447\r
0350b57c
HW
1448 //\r
1449 // Insert the async SCSI cmd to the Async I/O list\r
1450 //\r
1451 if (Event != NULL) {\r
7e4632a3 1452 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
0350b57c
HW
1453 TransReq->Packet = Packet;\r
1454 TransReq->CallerEvent = Event;\r
1455 InsertTailList (&Private->Queue, &TransReq->TransferList);\r
1456 gBS->RestoreTPL (OldTpl);\r
1457 }\r
1458\r
0591696e
FT
1459 //\r
1460 // Start to execute the transfer request.\r
1461 //\r
0350b57c
HW
1462 UfsStartExecCmd (Private, TransReq->Slot);\r
1463\r
1464 //\r
1465 // Immediately return for async I/O.\r
1466 //\r
1467 if (Event != NULL) {\r
1468 return EFI_SUCCESS;\r
1469 }\r
0591696e
FT
1470\r
1471 //\r
1472 // Wait for the completion of the transfer request.\r
095f0779 1473 // \r
13fca387 1474 Status = UfsWaitMemSet (Private, UFS_HC_UTRLDBR_OFFSET, BIT0 << TransReq->Slot, 0, Packet->Timeout);\r
0591696e
FT
1475 if (EFI_ERROR (Status)) {\r
1476 goto Exit;\r
1477 }\r
1478\r
1479 //\r
1480 // Get sense data if exists\r
1481 //\r
0350b57c 1482 Response = (UTP_RESPONSE_UPIU*)((UINT8*)TransReq->CmdDescHost + TransReq->Trd->RuO * sizeof (UINT32));\r
0591696e
FT
1483 ASSERT (Response != NULL);\r
1484 SenseDataLen = Response->SenseDataLen;\r
1485 SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));\r
1486 \r
1487 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {\r
1488 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);\r
1489 Packet->SenseDataLength = (UINT8)SenseDataLen;\r
1490 }\r
1491\r
1492 //\r
1493 // Check the transfer request result.\r
1494 //\r
1495 Packet->TargetStatus = Response->Status;\r
1496 if (Response->Response != 0) {\r
edd94e74 1497 DEBUG ((DEBUG_ERROR, "UfsExecScsiCmds() fails with Target Failure\n"));\r
0591696e
FT
1498 Status = EFI_DEVICE_ERROR;\r
1499 goto Exit;\r
1500 }\r
1501\r
0350b57c 1502 if (TransReq->Trd->Ocs == 0) {\r
0591696e
FT
1503 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
1504 if ((Response->Flags & BIT5) == BIT5) {\r
1505 ResTranCount = Response->ResTranCount;\r
1506 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
1507 Packet->InTransferLength -= ResTranCount;\r
1508 }\r
1509 } else {\r
1510 if ((Response->Flags & BIT5) == BIT5) {\r
1511 ResTranCount = Response->ResTranCount;\r
1512 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
1513 Packet->OutTransferLength -= ResTranCount;\r
1514 }\r
1515 }\r
1516 } else {\r
1517 Status = EFI_DEVICE_ERROR;\r
1518 }\r
1519\r
1520Exit:\r
1521 UfsHc->Flush (UfsHc);\r
1522\r
0350b57c 1523 UfsStopExecCmd (Private, TransReq->Slot);\r
0591696e 1524\r
0350b57c
HW
1525 if (TransReq->DataBufMapping != NULL) {\r
1526 UfsHc->Unmap (UfsHc, TransReq->DataBufMapping);\r
0591696e
FT
1527 }\r
1528\r
1529Exit1:\r
0350b57c
HW
1530 if (TransReq->CmdDescMapping != NULL) {\r
1531 UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);\r
0591696e 1532 }\r
0350b57c
HW
1533 if (TransReq->CmdDescHost != NULL) {\r
1534 UfsHc->FreeBuffer (UfsHc, EFI_SIZE_TO_PAGES (TransReq->CmdDescSize), TransReq->CmdDescHost);\r
1535 }\r
1536 if (TransReq != NULL) {\r
1537 FreePool (TransReq);\r
0591696e
FT
1538 }\r
1539 return Status;\r
1540}\r
1541\r
1542\r
1543/**\r
1544 Sent UIC DME_LINKSTARTUP command to start the link startup procedure.\r
1545\r
1546 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1547 @param[in] UicOpcode The opcode of the UIC command.\r
1548 @param[in] Arg1 The value for 1st argument of the UIC command.\r
1549 @param[in] Arg2 The value for 2nd argument of the UIC command.\r
1550 @param[in] Arg3 The value for 3rd argument of the UIC command.\r
1551\r
1552 @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device.\r
1553 @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device.\r
1554 @return EFI_NOT_FOUND The presence of the UFS device isn't detected.\r
1555\r
1556**/\r
1557EFI_STATUS\r
1558UfsExecUicCommands (\r
1559 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1560 IN UINT8 UicOpcode,\r
1561 IN UINT32 Arg1,\r
1562 IN UINT32 Arg2,\r
1563 IN UINT32 Arg3\r
1564 )\r
1565{\r
1566 EFI_STATUS Status;\r
0591696e 1567 UINT32 Data;\r
0591696e 1568\r
095f0779
FT
1569 Status = UfsMmioRead32 (Private, UFS_HC_IS_OFFSET, &Data);\r
1570 if (EFI_ERROR (Status)) {\r
1571 return Status;\r
1572 }\r
1573\r
0591696e
FT
1574 if ((Data & UFS_HC_IS_UCCS) == UFS_HC_IS_UCCS) {\r
1575 //\r
1576 // Clear IS.BIT10 UIC Command Completion Status (UCCS) at first.\r
1577 //\r
095f0779
FT
1578 Status = UfsMmioWrite32 (Private, UFS_HC_IS_OFFSET, Data);\r
1579 if (EFI_ERROR (Status)) {\r
1580 return Status;\r
1581 }\r
0591696e
FT
1582 }\r
1583\r
1584 //\r
1585 // When programming UIC command registers, host software shall set the register UICCMD\r
1586 // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3)\r
1587 // are set.\r
1588 //\r
095f0779
FT
1589 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG1_OFFSET, Arg1);\r
1590 if (EFI_ERROR (Status)) {\r
1591 return Status;\r
1592 }\r
0591696e 1593\r
095f0779
FT
1594 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG2_OFFSET, Arg2);\r
1595 if (EFI_ERROR (Status)) {\r
1596 return Status;\r
1597 }\r
0591696e 1598\r
095f0779
FT
1599 Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG3_OFFSET, Arg3);\r
1600 if (EFI_ERROR (Status)) {\r
1601 return Status;\r
1602 }\r
0591696e
FT
1603\r
1604 //\r
1605 // Host software shall only set the UICCMD if HCS.UCRDY is set to 1.\r
1606 //\r
095f0779 1607 Status = UfsWaitMemSet (Private, UFS_HC_STATUS_OFFSET, UFS_HC_HCS_UCRDY, UFS_HC_HCS_UCRDY, UFS_TIMEOUT);\r
0591696e
FT
1608 if (EFI_ERROR (Status)) {\r
1609 return Status;\r
1610 }\r
1611\r
095f0779
FT
1612 Status = UfsMmioWrite32 (Private, UFS_HC_UIC_CMD_OFFSET, (UINT32)UicOpcode);\r
1613 if (EFI_ERROR (Status)) {\r
1614 return Status;\r
1615 }\r
0591696e
FT
1616\r
1617 //\r
1618 // UFS 2.0 spec section 5.3.1 Offset:0x20 IS.Bit10 UIC Command Completion Status (UCCS)\r
1619 // This bit is set to '1' by the host controller upon completion of a UIC command. \r
1620 //\r
095f0779 1621 Status = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_UCCS, UFS_HC_IS_UCCS, UFS_TIMEOUT);\r
0591696e
FT
1622 if (EFI_ERROR (Status)) {\r
1623 return Status;\r
1624 }\r
1625\r
1626 if (UicOpcode != UfsUicDmeReset) {\r
095f0779
FT
1627 Status = UfsMmioRead32 (Private, UFS_HC_UCMD_ARG2_OFFSET, &Data);\r
1628 if (EFI_ERROR (Status)) {\r
1629 return Status;\r
1630 }\r
0591696e
FT
1631 if ((Data & 0xFF) != 0) {\r
1632 DEBUG_CODE_BEGIN();\r
1633 DumpUicCmdExecResult (UicOpcode, (UINT8)(Data & 0xFF));\r
1634 DEBUG_CODE_END();\r
1635 return EFI_DEVICE_ERROR;\r
1636 }\r
1637 }\r
1638\r
1639 //\r
1640 // Check value of HCS.DP and make sure that there is a device attached to the Link.\r
1641 //\r
095f0779
FT
1642 Status = UfsMmioRead32 (Private, UFS_HC_STATUS_OFFSET, &Data);\r
1643 if (EFI_ERROR (Status)) {\r
1644 return Status;\r
1645 }\r
1646\r
0591696e 1647 if ((Data & UFS_HC_HCS_DP) == 0) {\r
095f0779 1648 Status = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT);\r
0591696e
FT
1649 if (EFI_ERROR (Status)) {\r
1650 return EFI_DEVICE_ERROR;\r
1651 }\r
1652 return EFI_NOT_FOUND;\r
1653 }\r
1654\r
edd94e74 1655 DEBUG ((DEBUG_INFO, "UfsPassThruDxe: found a attached UFS device\n"));\r
0591696e
FT
1656\r
1657 return EFI_SUCCESS;\r
1658}\r
1659\r
1660/**\r
1661 Allocate common buffer for host and UFS bus master access simultaneously.\r
1662\r
1663 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1664 @param[in] Size The length of buffer to be allocated.\r
1665 @param[out] CmdDescHost A pointer to store the base system memory address of the allocated range.\r
1666 @param[out] CmdDescPhyAddr The resulting map address for the UFS bus master to use to access the hosts CmdDescHost.\r
1667 @param[out] CmdDescMapping A resulting value to pass to Unmap().\r
1668\r
1669 @retval EFI_SUCCESS The common buffer was allocated successfully.\r
1670 @retval EFI_DEVICE_ERROR The allocation fails.\r
1671 @retval EFI_OUT_OF_RESOURCES The memory resource is insufficient.\r
1672\r
1673**/\r
1674EFI_STATUS\r
1675UfsAllocateAlignCommonBuffer (\r
1676 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
1677 IN UINTN Size,\r
1678 OUT VOID **CmdDescHost,\r
1679 OUT EFI_PHYSICAL_ADDRESS *CmdDescPhyAddr,\r
1680 OUT VOID **CmdDescMapping\r
1681 )\r
1682{\r
1683 EFI_STATUS Status;\r
1684 UINTN Bytes;\r
1685 BOOLEAN Is32BitAddr;\r
1686 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
1687\r
1688 if ((Private->Capabilities & UFS_HC_CAP_64ADDR) == UFS_HC_CAP_64ADDR) {\r
0591696e 1689 Is32BitAddr = FALSE;\r
a2e3feb6
HZ
1690 } else {\r
1691 Is32BitAddr = TRUE;\r
0591696e
FT
1692 }\r
1693\r
1694 UfsHc = Private->UfsHostController;\r
1695 Status = UfsHc->AllocateBuffer (\r
1696 UfsHc,\r
1697 AllocateAnyPages,\r
1698 EfiBootServicesData,\r
1699 EFI_SIZE_TO_PAGES (Size),\r
1700 CmdDescHost,\r
1701 0\r
1702 );\r
1703 if (EFI_ERROR (Status)) {\r
1704 *CmdDescMapping = NULL;\r
1705 *CmdDescHost = NULL;\r
1706 *CmdDescPhyAddr = 0;\r
1707 return EFI_OUT_OF_RESOURCES;\r
1708 }\r
1709\r
1710 Bytes = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size));\r
1711 Status = UfsHc->Map (\r
1712 UfsHc,\r
1713 EdkiiUfsHcOperationBusMasterCommonBuffer,\r
1714 *CmdDescHost,\r
1715 &Bytes,\r
1716 CmdDescPhyAddr,\r
1717 CmdDescMapping\r
1718 );\r
1719\r
1720 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)))) {\r
1721 UfsHc->FreeBuffer (\r
1722 UfsHc,\r
1723 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),\r
1724 *CmdDescHost\r
1725 );\r
1726 *CmdDescHost = NULL;\r
1727 return EFI_OUT_OF_RESOURCES;\r
1728 }\r
1729\r
1730 if (Is32BitAddr && ((*CmdDescPhyAddr) > 0x100000000ULL)) {\r
1731 //\r
1732 // The UFS host controller doesn't support 64bit addressing, so should not get a >4G UFS bus master address.\r
1733 //\r
1734 UfsHc->Unmap (\r
1735 UfsHc,\r
1736 *CmdDescMapping\r
1737 );\r
1738 UfsHc->FreeBuffer (\r
1739 UfsHc,\r
1740 EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)),\r
1741 *CmdDescHost\r
1742 );\r
1743 *CmdDescMapping = NULL;\r
1744 *CmdDescHost = NULL;\r
1745 return EFI_DEVICE_ERROR;\r
1746 }\r
1747\r
1748 ZeroMem (*CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Size)));\r
1749 return EFI_SUCCESS;\r
1750}\r
1751\r
1752/**\r
1753 Enable the UFS host controller for accessing.\r
1754\r
1755 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1756\r
1757 @retval EFI_SUCCESS The UFS host controller enabling was executed successfully.\r
1758 @retval EFI_DEVICE_ERROR A device error occurred while enabling the UFS host controller.\r
1759\r
1760**/\r
1761EFI_STATUS\r
1762UfsEnableHostController (\r
1763 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
1764 )\r
1765{\r
1766 EFI_STATUS Status;\r
0591696e
FT
1767 UINT32 Data;\r
1768\r
1769 //\r
1770 // UFS 2.0 spec section 7.1.1 - Host Controller Initialization\r
1771 //\r
1772 // Reinitialize the UFS host controller if HCE bit of HC register is set.\r
1773 //\r
095f0779
FT
1774 Status = UfsMmioRead32 (Private, UFS_HC_ENABLE_OFFSET, &Data);\r
1775 if (EFI_ERROR (Status)) {\r
1776 return Status;\r
1777 }\r
1778\r
0591696e
FT
1779 if ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN) {\r
1780 //\r
1781 // Write a 0 to the HCE register at first to disable the host controller.\r
1782 //\r
095f0779
FT
1783 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, 0);\r
1784 if (EFI_ERROR (Status)) {\r
1785 return Status;\r
1786 }\r
0591696e
FT
1787 //\r
1788 // Wait until HCE is read as '0' before continuing.\r
1789 //\r
095f0779 1790 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);\r
0591696e
FT
1791 if (EFI_ERROR (Status)) {\r
1792 return EFI_DEVICE_ERROR;\r
1793 }\r
1794 }\r
1795\r
1796 //\r
1797 // Write a 1 to the HCE register to enable the UFS host controller.\r
1798 //\r
095f0779
FT
1799 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN);\r
1800 if (EFI_ERROR (Status)) {\r
1801 return Status;\r
1802 }\r
1803\r
0591696e
FT
1804 //\r
1805 // Wait until HCE is read as '1' before continuing.\r
1806 //\r
095f0779 1807 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, UFS_HC_HCE_EN, UFS_TIMEOUT);\r
0591696e
FT
1808 if (EFI_ERROR (Status)) {\r
1809 return EFI_DEVICE_ERROR;\r
1810 }\r
1811\r
1812 return EFI_SUCCESS;\r
1813}\r
1814\r
1815/**\r
1816 Detect if a UFS device attached.\r
1817\r
1818 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1819\r
1820 @retval EFI_SUCCESS The UFS device detection was executed successfully.\r
1821 @retval EFI_NOT_FOUND Not found a UFS device attached.\r
1822 @retval EFI_DEVICE_ERROR A device error occurred while detecting the UFS device.\r
1823\r
1824**/\r
1825EFI_STATUS\r
1826UfsDeviceDetection (\r
1827 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
1828 )\r
1829{\r
1830 UINTN Retry;\r
1831 EFI_STATUS Status;\r
1832\r
1833 //\r
1834 // Start UFS device detection.\r
1835 // Try up to 3 times for establishing data link with device.\r
1836 //\r
1837 for (Retry = 0; Retry < 3; Retry++) {\r
1838 Status = UfsExecUicCommands (Private, UfsUicDmeLinkStartup, 0, 0, 0);\r
1839 if (!EFI_ERROR (Status)) {\r
1840 break;\r
1841 }\r
1842\r
1843 if (Status == EFI_NOT_FOUND) {\r
1844 continue;\r
1845 }\r
1846\r
1847 return EFI_DEVICE_ERROR;\r
1848 }\r
1849\r
1850 if (Retry == 3) {\r
1851 return EFI_NOT_FOUND;\r
1852 }\r
1853\r
1854 return EFI_SUCCESS;\r
1855}\r
1856\r
1857/**\r
1858 Initialize UFS task management request list related h/w context.\r
1859\r
1860 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1861\r
1862 @retval EFI_SUCCESS The UFS task management list was initialzed successfully.\r
1863 @retval EFI_DEVICE_ERROR The initialization fails.\r
1864\r
1865**/\r
1866EFI_STATUS\r
1867UfsInitTaskManagementRequestList (\r
1868 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
1869 )\r
1870{\r
0591696e
FT
1871 UINT32 Data;\r
1872 UINT8 Nutmrs;\r
1873 VOID *CmdDescHost;\r
1874 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
1875 VOID *CmdDescMapping;\r
1876 EFI_STATUS Status;\r
1877 \r
1878 //\r
1879 // Initial h/w and s/w context for future operations.\r
1880 //\r
1881 CmdDescHost = NULL;\r
1882 CmdDescMapping = NULL;\r
1883 CmdDescPhyAddr = 0;\r
095f0779
FT
1884\r
1885 Status = UfsMmioRead32 (Private, UFS_HC_CAP_OFFSET, &Data);\r
1886 if (EFI_ERROR (Status)) {\r
1887 return Status;\r
1888 }\r
1889\r
0591696e
FT
1890 Private->Capabilities = Data;\r
1891\r
1892 //\r
1893 // Allocate and initialize UTP Task Management Request List.\r
1894 //\r
1895 Nutmrs = (UINT8) (RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);\r
1896 Status = UfsAllocateAlignCommonBuffer (Private, Nutmrs * sizeof (UTP_TMRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);\r
1897 if (EFI_ERROR (Status)) {\r
1898 return Status;\r
1899 }\r
1900\r
1901 //\r
1902 // Program the UTP Task Management Request List Base Address and UTP Task Management\r
1903 // Request List Base Address with a 64-bit address allocated at step 6.\r
1904 //\r
095f0779
FT
1905 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLBA_OFFSET, (UINT32)(UINTN)CmdDescPhyAddr);\r
1906 if (EFI_ERROR (Status)) {\r
1907 return Status;\r
1908 }\r
1909\r
1910 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLBAU_OFFSET, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));\r
1911 if (EFI_ERROR (Status)) {\r
1912 return Status;\r
1913 }\r
0591696e
FT
1914 Private->UtpTmrlBase = CmdDescHost;\r
1915 Private->Nutmrs = Nutmrs;\r
1916 Private->TmrlMapping = CmdDescMapping;\r
1917\r
1918 //\r
1919 // Enable the UTP Task Management Request List by setting the UTP Task Management\r
1920 // Request List RunStop Register (UTMRLRSR) to '1'.\r
1921 //\r
095f0779
FT
1922 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLRSR_OFFSET, UFS_HC_UTMRLRSR);\r
1923 if (EFI_ERROR (Status)) {\r
1924 return Status;\r
1925 }\r
0591696e
FT
1926\r
1927 return EFI_SUCCESS;\r
1928}\r
1929\r
1930/**\r
1931 Initialize UFS transfer request list related h/w context.\r
1932\r
1933 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
1934\r
1935 @retval EFI_SUCCESS The UFS transfer list was initialzed successfully.\r
1936 @retval EFI_DEVICE_ERROR The initialization fails.\r
1937\r
1938**/\r
1939EFI_STATUS\r
1940UfsInitTransferRequestList (\r
1941 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
1942 )\r
1943{\r
0591696e
FT
1944 UINT32 Data;\r
1945 UINT8 Nutrs;\r
1946 VOID *CmdDescHost;\r
1947 EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;\r
1948 VOID *CmdDescMapping; \r
1949 EFI_STATUS Status;\r
1950\r
1951 //\r
1952 // Initial h/w and s/w context for future operations.\r
1953 //\r
1954 CmdDescHost = NULL;\r
1955 CmdDescMapping = NULL;\r
1956 CmdDescPhyAddr = 0;\r
095f0779
FT
1957\r
1958 Status = UfsMmioRead32 (Private, UFS_HC_CAP_OFFSET, &Data);\r
1959 if (EFI_ERROR (Status)) {\r
1960 return Status;\r
1961 }\r
1962\r
0591696e
FT
1963 Private->Capabilities = Data;\r
1964\r
1965 //\r
1966 // Allocate and initialize UTP Transfer Request List.\r
1967 //\r
1968 Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);\r
1969 Status = UfsAllocateAlignCommonBuffer (Private, Nutrs * sizeof (UTP_TRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping);\r
1970 if (EFI_ERROR (Status)) {\r
1971 return Status;\r
1972 }\r
1973\r
1974 //\r
1975 // Program the UTP Transfer Request List Base Address and UTP Transfer Request List\r
1976 // Base Address with a 64-bit address allocated at step 8.\r
1977 //\r
095f0779
FT
1978 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLBA_OFFSET, (UINT32)(UINTN)CmdDescPhyAddr);\r
1979 if (EFI_ERROR (Status)) {\r
1980 return Status;\r
1981 }\r
1982\r
1983 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLBAU_OFFSET, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));\r
1984 if (EFI_ERROR (Status)) {\r
1985 return Status;\r
1986 }\r
1987\r
0591696e
FT
1988 Private->UtpTrlBase = CmdDescHost;\r
1989 Private->Nutrs = Nutrs; \r
1990 Private->TrlMapping = CmdDescMapping;\r
1991\r
1992 //\r
1993 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List\r
1994 // RunStop Register (UTRLRSR) to '1'.\r
1995 //\r
095f0779
FT
1996 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, UFS_HC_UTRLRSR);\r
1997 if (EFI_ERROR (Status)) {\r
1998 return Status;\r
1999 }\r
0591696e
FT
2000\r
2001 return EFI_SUCCESS;\r
2002}\r
2003\r
2004/**\r
2005 Initialize the UFS host controller.\r
2006\r
2007 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
2008\r
2009 @retval EFI_SUCCESS The Ufs Host Controller is initialized successfully.\r
2010 @retval Others A device error occurred while initializing the controller.\r
2011\r
2012**/\r
2013EFI_STATUS\r
2014UfsControllerInit (\r
2015 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
2016 )\r
2017{\r
2018 EFI_STATUS Status;\r
2019\r
2020 Status = UfsEnableHostController (Private);\r
2021 if (EFI_ERROR (Status)) {\r
edd94e74 2022 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Enable Host Controller Fails, Status = %r\n", Status));\r
0591696e
FT
2023 return Status;\r
2024 }\r
2025\r
2026 Status = UfsDeviceDetection (Private);\r
2027 if (EFI_ERROR (Status)) {\r
edd94e74 2028 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Device Detection Fails, Status = %r\n", Status));\r
0591696e
FT
2029 return Status;\r
2030 }\r
2031\r
2032 Status = UfsInitTaskManagementRequestList (Private);\r
2033 if (EFI_ERROR (Status)) {\r
edd94e74 2034 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Task management list initialization Fails, Status = %r\n", Status));\r
0591696e
FT
2035 return Status;\r
2036 }\r
2037\r
2038 Status = UfsInitTransferRequestList (Private);\r
2039 if (EFI_ERROR (Status)) {\r
edd94e74 2040 DEBUG ((DEBUG_ERROR, "UfsControllerInit: Transfer list initialization Fails, Status = %r\n", Status));\r
0591696e
FT
2041 return Status;\r
2042 }\r
2043\r
edd94e74 2044 DEBUG ((DEBUG_INFO, "UfsControllerInit Finished\n"));\r
0591696e
FT
2045 return EFI_SUCCESS;\r
2046}\r
2047\r
2048/**\r
2049 Stop the UFS host controller.\r
2050\r
2051 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure.\r
2052\r
2053 @retval EFI_SUCCESS The Ufs Host Controller is stopped successfully.\r
2054 @retval Others A device error occurred while stopping the controller.\r
2055\r
2056**/\r
2057EFI_STATUS\r
2058UfsControllerStop (\r
2059 IN UFS_PASS_THRU_PRIVATE_DATA *Private\r
2060 )\r
2061{\r
2062 EFI_STATUS Status;\r
0591696e
FT
2063 UINT32 Data;\r
2064\r
2065 //\r
2066 // Enable the UTP Task Management Request List by setting the UTP Task Management\r
2067 // Request List RunStop Register (UTMRLRSR) to '1'.\r
2068 //\r
095f0779
FT
2069 Status = UfsMmioWrite32 (Private, UFS_HC_UTMRLRSR_OFFSET, 0);\r
2070 if (EFI_ERROR (Status)) {\r
2071 return Status;\r
2072 }\r
0591696e
FT
2073\r
2074 //\r
2075 // Enable the UTP Transfer Request List by setting the UTP Transfer Request List\r
2076 // RunStop Register (UTRLRSR) to '1'.\r
2077 //\r
095f0779
FT
2078 Status = UfsMmioWrite32 (Private, UFS_HC_UTRLRSR_OFFSET, 0);\r
2079 if (EFI_ERROR (Status)) {\r
2080 return Status;\r
2081 }\r
0591696e
FT
2082\r
2083 //\r
2084 // Write a 0 to the HCE register in order to disable the host controller.\r
2085 //\r
095f0779
FT
2086 Status = UfsMmioRead32 (Private, UFS_HC_ENABLE_OFFSET, &Data);\r
2087 if (EFI_ERROR (Status)) {\r
2088 return Status;\r
2089 }\r
0591696e 2090 ASSERT ((Data & UFS_HC_HCE_EN) == UFS_HC_HCE_EN);\r
095f0779
FT
2091\r
2092 Status = UfsMmioWrite32 (Private, UFS_HC_ENABLE_OFFSET, 0);\r
2093 if (EFI_ERROR (Status)) {\r
2094 return Status;\r
2095 }\r
0591696e
FT
2096\r
2097 //\r
2098 // Wait until HCE is read as '0' before continuing.\r
2099 //\r
095f0779 2100 Status = UfsWaitMemSet (Private, UFS_HC_ENABLE_OFFSET, UFS_HC_HCE_EN, 0, UFS_TIMEOUT);\r
0591696e
FT
2101 if (EFI_ERROR (Status)) {\r
2102 return EFI_DEVICE_ERROR;\r
2103 }\r
2104\r
edd94e74 2105 DEBUG ((DEBUG_INFO, "UfsController is stopped\n"));\r
0591696e
FT
2106\r
2107 return EFI_SUCCESS;\r
2108}\r
2109\r
0350b57c
HW
2110\r
2111/**\r
2112 Internal helper function which will signal the caller event and clean up\r
2113 resources.\r
2114\r
2115 @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data\r
2116 structure.\r
2117 @param[in] TransReq The pointer to the UFS_PASS_THRU_TRANS_REQ data\r
2118 structure.\r
2119\r
2120**/\r
2121VOID\r
2122EFIAPI\r
2123SignalCallerEvent (\r
2124 IN UFS_PASS_THRU_PRIVATE_DATA *Private,\r
2125 IN UFS_PASS_THRU_TRANS_REQ *TransReq\r
2126 )\r
2127{\r
2128 EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc;\r
2129 EFI_EVENT CallerEvent;\r
2130\r
33e2ba78
HW
2131 ASSERT ((Private != NULL) && (TransReq != NULL));\r
2132\r
0350b57c
HW
2133 UfsHc = Private->UfsHostController;\r
2134 CallerEvent = TransReq->CallerEvent;\r
2135\r
2136 RemoveEntryList (&TransReq->TransferList);\r
2137\r
2138 UfsHc->Flush (UfsHc);\r
2139\r
2140 UfsStopExecCmd (Private, TransReq->Slot);\r
2141\r
2142 if (TransReq->DataBufMapping != NULL) {\r
2143 UfsHc->Unmap (UfsHc, TransReq->DataBufMapping);\r
2144 }\r
2145\r
2146 if (TransReq->CmdDescMapping != NULL) {\r
2147 UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping);\r
2148 }\r
2149 if (TransReq->CmdDescHost != NULL) {\r
2150 UfsHc->FreeBuffer (\r
2151 UfsHc,\r
2152 EFI_SIZE_TO_PAGES (TransReq->CmdDescSize),\r
2153 TransReq->CmdDescHost\r
2154 );\r
2155 }\r
33e2ba78
HW
2156\r
2157 FreePool (TransReq);\r
0350b57c
HW
2158\r
2159 gBS->SignalEvent (CallerEvent);\r
2160 return;\r
2161}\r
2162\r
2163/**\r
2164 Call back function when the timer event is signaled.\r
2165\r
2166 @param[in] Event The Event this notify function registered to.\r
2167 @param[in] Context Pointer to the context data registered to the Event.\r
2168\r
2169**/\r
2170VOID\r
2171EFIAPI\r
2172ProcessAsyncTaskList (\r
2173 IN EFI_EVENT Event,\r
2174 IN VOID *Context\r
2175 )\r
2176{\r
2177 UFS_PASS_THRU_PRIVATE_DATA *Private;\r
2178 LIST_ENTRY *Entry;\r
2179 LIST_ENTRY *NextEntry;\r
2180 UFS_PASS_THRU_TRANS_REQ *TransReq;\r
2181 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet;\r
2182 UTP_RESPONSE_UPIU *Response;\r
2183 UINT16 SenseDataLen;\r
2184 UINT32 ResTranCount;\r
2185 UINT32 SlotsMap;\r
2186 UINT32 Value;\r
2187 EFI_STATUS Status;\r
2188\r
2189 Private = (UFS_PASS_THRU_PRIVATE_DATA*) Context;\r
2190 SlotsMap = 0;\r
2191\r
2192 //\r
2193 // Check the entries in the async I/O queue are done or not.\r
2194 //\r
2195 if (!IsListEmpty(&Private->Queue)) {\r
2196 EFI_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->Queue) {\r
2197 TransReq = UFS_PASS_THRU_TRANS_REQ_FROM_THIS (Entry);\r
2198 Packet = TransReq->Packet;\r
2199\r
2200 if ((SlotsMap & (BIT0 << TransReq->Slot)) != 0) {\r
2201 return;\r
2202 }\r
2203 SlotsMap |= BIT0 << TransReq->Slot;\r
2204\r
2205 Status = UfsMmioRead32 (Private, UFS_HC_UTRLDBR_OFFSET, &Value);\r
2206 if (EFI_ERROR (Status)) {\r
2207 //\r
2208 // TODO: Should find/add a proper host adapter return status for this\r
2209 // case.\r
2210 //\r
2211 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR;\r
edd94e74 2212 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p UfsMmioRead32() Error.\n", TransReq->CallerEvent));\r
0350b57c
HW
2213 SignalCallerEvent (Private, TransReq);\r
2214 continue;\r
2215 }\r
2216\r
2217 if ((Value & (BIT0 << TransReq->Slot)) != 0) {\r
2218 //\r
2219 // Scsi cmd not finished yet.\r
2220 //\r
2221 if (TransReq->TimeoutRemain > UFS_HC_ASYNC_TIMER) {\r
2222 TransReq->TimeoutRemain -= UFS_HC_ASYNC_TIMER;\r
2223 continue;\r
2224 } else {\r
2225 //\r
2226 // Timeout occurs.\r
2227 //\r
2228 Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND;\r
edd94e74 2229 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT.\n", TransReq->CallerEvent));\r
0350b57c
HW
2230 SignalCallerEvent (Private, TransReq);\r
2231 continue;\r
2232 }\r
2233 } else {\r
2234 //\r
2235 // Scsi cmd finished.\r
2236 //\r
2237 // Get sense data if exists\r
2238 //\r
2239 Response = (UTP_RESPONSE_UPIU*)((UINT8*)TransReq->CmdDescHost + TransReq->Trd->RuO * sizeof (UINT32));\r
2240 ASSERT (Response != NULL);\r
2241 SenseDataLen = Response->SenseDataLen;\r
2242 SwapLittleEndianToBigEndian ((UINT8*)&SenseDataLen, sizeof (UINT16));\r
2243\r
2244 if ((Packet->SenseDataLength != 0) && (Packet->SenseData != NULL)) {\r
2245 CopyMem (Packet->SenseData, Response->SenseData, SenseDataLen);\r
2246 Packet->SenseDataLength = (UINT8)SenseDataLen;\r
2247 }\r
2248\r
2249 //\r
2250 // Check the transfer request result.\r
2251 //\r
2252 Packet->TargetStatus = Response->Status;\r
2253 if (Response->Response != 0) {\r
edd94e74 2254 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Failure.\n", TransReq->CallerEvent));\r
0350b57c
HW
2255 SignalCallerEvent (Private, TransReq);\r
2256 continue;\r
2257 }\r
2258\r
2259 if (TransReq->Trd->Ocs == 0) {\r
2260 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
2261 if ((Response->Flags & BIT5) == BIT5) {\r
2262 ResTranCount = Response->ResTranCount;\r
2263 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
2264 Packet->InTransferLength -= ResTranCount;\r
2265 }\r
2266 } else {\r
2267 if ((Response->Flags & BIT5) == BIT5) {\r
2268 ResTranCount = Response->ResTranCount;\r
2269 SwapLittleEndianToBigEndian ((UINT8*)&ResTranCount, sizeof (UINT32));\r
2270 Packet->OutTransferLength -= ResTranCount;\r
2271 }\r
2272 }\r
2273 } else {\r
edd94e74 2274 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Target Device Error.\n", TransReq->CallerEvent));\r
0350b57c
HW
2275 SignalCallerEvent (Private, TransReq);\r
2276 continue;\r
2277 }\r
2278\r
edd94e74 2279 DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p Success.\n", TransReq->CallerEvent));\r
0350b57c
HW
2280 SignalCallerEvent (Private, TransReq);\r
2281 }\r
2282 }\r
2283 }\r
2284}\r
2285\r