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