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