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