]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Tcg/Opal/OpalPassword/OpalAhciMode.c
OvmfPkg/LockBoxLib: Update the comments for API UpdateLockBox()
[mirror_edk2.git] / SecurityPkg / Tcg / Opal / OpalPassword / OpalAhciMode.c
1 /** @file
2 This driver is used for Opal Password Feature support at AHCI mode.
3
4 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15
16 #include "OpalPasswordPei.h"
17
18 /**
19 Start command for give slot on specific port.
20
21 @param AhciBar AHCI bar address.
22 @param Port The number of port.
23 @param CommandSlot The number of CommandSlot.
24 @param Timeout The timeout Value of start.
25
26 @retval EFI_DEVICE_ERROR The command start unsuccessfully.
27 @retval EFI_TIMEOUT The operation is time out.
28 @retval EFI_SUCCESS The command start successfully.
29
30 **/
31 EFI_STATUS
32 EFIAPI
33 AhciStartCommand (
34 IN UINT32 AhciBar,
35 IN UINT8 Port,
36 IN UINT8 CommandSlot,
37 IN UINT64 Timeout
38 );
39
40 /**
41 Stop command running for giving port
42
43 @param AhciBar AHCI bar address.
44 @param Port The number of port.
45 @param Timeout The timeout Value of stop.
46
47 @retval EFI_DEVICE_ERROR The command stop unsuccessfully.
48 @retval EFI_TIMEOUT The operation is time out.
49 @retval EFI_SUCCESS The command stop successfully.
50
51 **/
52 EFI_STATUS
53 EFIAPI
54 AhciStopCommand (
55 IN UINT32 AhciBar,
56 IN UINT8 Port,
57 IN UINT64 Timeout
58 );
59
60 /**
61 Read AHCI Operation register.
62
63 @param AhciBar AHCI bar address.
64 @param Offset The operation register offset.
65
66 @return The register content read.
67
68 **/
69 UINT32
70 EFIAPI
71 AhciReadReg (
72 IN UINT32 AhciBar,
73 IN UINT32 Offset
74 )
75 {
76 UINT32 Data;
77
78 Data = 0;
79
80 Data = MmioRead32 (AhciBar + Offset);
81
82 return Data;
83 }
84
85 /**
86 Write AHCI Operation register.
87
88 @param AhciBar AHCI bar address.
89 @param Offset The operation register offset.
90 @param Data The Data used to write down.
91
92 **/
93 VOID
94 EFIAPI
95 AhciWriteReg (
96 IN UINT32 AhciBar,
97 IN UINT32 Offset,
98 IN UINT32 Data
99 )
100 {
101 MmioWrite32 (AhciBar + Offset, Data);
102
103 return ;
104 }
105
106 /**
107 Do AND operation with the Value of AHCI Operation register.
108
109 @param AhciBar AHCI bar address.
110 @param Offset The operation register offset.
111 @param AndData The Data used to do AND operation.
112
113 **/
114 VOID
115 EFIAPI
116 AhciAndReg (
117 IN UINT32 AhciBar,
118 IN UINT32 Offset,
119 IN UINT32 AndData
120 )
121 {
122 UINT32 Data;
123
124 Data = AhciReadReg (AhciBar, Offset);
125
126 Data &= AndData;
127
128 AhciWriteReg (AhciBar, Offset, Data);
129 }
130
131 /**
132 Do OR operation with the Value of AHCI Operation register.
133
134 @param AhciBar AHCI bar address.
135 @param Offset The operation register offset.
136 @param OrData The Data used to do OR operation.
137
138 **/
139 VOID
140 EFIAPI
141 AhciOrReg (
142 IN UINT32 AhciBar,
143 IN UINT32 Offset,
144 IN UINT32 OrData
145 )
146 {
147 UINT32 Data;
148
149 Data = AhciReadReg (AhciBar, Offset);
150
151 Data |= OrData;
152
153 AhciWriteReg (AhciBar, Offset, Data);
154 }
155
156 /**
157 Wait for memory set to the test Value.
158
159 @param AhciBar AHCI bar address.
160 @param Offset The memory offset to test.
161 @param MaskValue The mask Value of memory.
162 @param TestValue The test Value of memory.
163 @param Timeout The time out Value for wait memory set.
164
165 @retval EFI_DEVICE_ERROR The memory is not set.
166 @retval EFI_TIMEOUT The memory setting is time out.
167 @retval EFI_SUCCESS The memory is correct set.
168
169 **/
170 EFI_STATUS
171 EFIAPI
172 AhciWaitMmioSet (
173 IN UINT32 AhciBar,
174 IN UINT32 Offset,
175 IN UINT32 MaskValue,
176 IN UINT32 TestValue,
177 IN UINT64 Timeout
178 )
179 {
180 UINT32 Value;
181 UINT32 Delay;
182
183 Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
184
185 do {
186 Value = AhciReadReg (AhciBar, Offset) & MaskValue;
187
188 if (Value == TestValue) {
189 return EFI_SUCCESS;
190 }
191
192 //
193 // Stall for 100 microseconds.
194 //
195 MicroSecondDelay (100);
196
197 Delay--;
198
199 } while (Delay > 0);
200
201 return EFI_TIMEOUT;
202 }
203 /**
204 Wait for the Value of the specified system memory set to the test Value.
205
206 @param Address The system memory address to test.
207 @param MaskValue The mask Value of memory.
208 @param TestValue The test Value of memory.
209 @param Timeout The time out Value for wait memory set, uses 100ns as a unit.
210
211 @retval EFI_TIMEOUT The system memory setting is time out.
212 @retval EFI_SUCCESS The system memory is correct set.
213
214 **/
215 EFI_STATUS
216 EFIAPI
217 AhciWaitMemSet (
218 IN EFI_PHYSICAL_ADDRESS Address,
219 IN UINT32 MaskValue,
220 IN UINT32 TestValue,
221 IN UINT64 Timeout
222 )
223 {
224 UINT32 Value;
225 UINT32 Delay;
226
227 Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);
228
229 do {
230 //
231 // Access sytem memory to see if the Value is the tested one.
232 //
233 // The system memory pointed by Address will be updated by the
234 // SATA Host Controller, "volatile" is introduced to prevent
235 // compiler from optimizing the access to the memory address
236 // to only read once.
237 //
238 Value = *(volatile UINT32 *) (UINTN) Address;
239 Value &= MaskValue;
240
241 if (Value == TestValue) {
242 return EFI_SUCCESS;
243 }
244
245 //
246 // Stall for 100 microseconds.
247 //
248 MicroSecondDelay (100);
249
250 Delay--;
251
252 } while (Delay > 0);
253
254 return EFI_TIMEOUT;
255 }
256
257 /**
258 Check the memory status to the test Value.
259
260 @param[in] Address The memory address to test.
261 @param[in] MaskValue The mask Value of memory.
262 @param[in] TestValue The test Value of memory.
263 @param[in, out] RetryTimes The retry times Value for waitting memory set. If 0, then just try once.
264
265 @retval EFI_NOTREADY The memory is not set.
266 @retval EFI_TIMEOUT The memory setting retry times out.
267 @retval EFI_SUCCESS The memory is correct set.
268
269 **/
270 EFI_STATUS
271 EFIAPI
272 AhciCheckMemSet (
273 IN UINTN Address,
274 IN UINT32 MaskValue,
275 IN UINT32 TestValue,
276 IN OUT UINTN *RetryTimes OPTIONAL
277 )
278 {
279 UINT32 Value;
280
281 if (RetryTimes != NULL) {
282 (*RetryTimes)--;
283 }
284
285 Value = *(volatile UINT32 *) Address;
286 Value &= MaskValue;
287
288 if (Value == TestValue) {
289 return EFI_SUCCESS;
290 }
291
292 if ((RetryTimes != NULL) && (*RetryTimes == 0)) {
293 return EFI_TIMEOUT;
294 } else {
295 return EFI_NOT_READY;
296 }
297 }
298
299 /**
300 Clear the port interrupt and error status. It will also clear
301 HBA interrupt status.
302
303 @param AhciBar AHCI bar address.
304 @param Port The number of port.
305
306 **/
307 VOID
308 EFIAPI
309 AhciClearPortStatus (
310 IN UINT32 AhciBar,
311 IN UINT8 Port
312 )
313 {
314 UINT32 Offset;
315
316 //
317 // Clear any error status
318 //
319 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;
320 AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset));
321
322 //
323 // Clear any port interrupt status
324 //
325 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;
326 AhciWriteReg (AhciBar, Offset, AhciReadReg (AhciBar, Offset));
327
328 //
329 // Clear any HBA interrupt status
330 //
331 AhciWriteReg (AhciBar, EFI_AHCI_IS_OFFSET, AhciReadReg (AhciBar, EFI_AHCI_IS_OFFSET));
332 }
333
334 /**
335 Enable the FIS running for giving port.
336
337 @param AhciBar AHCI bar address.
338 @param Port The number of port.
339 @param Timeout The timeout Value of enabling FIS.
340
341 @retval EFI_DEVICE_ERROR The FIS enable setting fails.
342 @retval EFI_TIMEOUT The FIS enable setting is time out.
343 @retval EFI_SUCCESS The FIS enable successfully.
344
345 **/
346 EFI_STATUS
347 EFIAPI
348 AhciEnableFisReceive (
349 IN UINT32 AhciBar,
350 IN UINT8 Port,
351 IN UINT64 Timeout
352 )
353 {
354 UINT32 Offset;
355
356 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
357 AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_FRE);
358
359 return AhciWaitMmioSet (
360 AhciBar,
361 Offset,
362 EFI_AHCI_PORT_CMD_FR,
363 EFI_AHCI_PORT_CMD_FR,
364 Timeout
365 );
366 }
367
368 /**
369 Disable the FIS running for giving port.
370
371 @param AhciBar AHCI bar address.
372 @param Port The number of port.
373 @param Timeout The timeout Value of disabling FIS.
374
375 @retval EFI_DEVICE_ERROR The FIS disable setting fails.
376 @retval EFI_TIMEOUT The FIS disable setting is time out.
377 @retval EFI_UNSUPPORTED The port is in running state.
378 @retval EFI_SUCCESS The FIS disable successfully.
379
380 **/
381 EFI_STATUS
382 EFIAPI
383 AhciDisableFisReceive (
384 IN UINT32 AhciBar,
385 IN UINT8 Port,
386 IN UINT64 Timeout
387 )
388 {
389 UINT32 Offset;
390 UINT32 Data;
391
392 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
393 Data = AhciReadReg (AhciBar, Offset);
394
395 //
396 // Before disabling Fis receive, the DMA engine of the port should NOT be in running status.
397 //
398 if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) != 0) {
399 return EFI_UNSUPPORTED;
400 }
401
402 //
403 // Check if the Fis receive DMA engine for the port is running.
404 //
405 if ((Data & EFI_AHCI_PORT_CMD_FR) != EFI_AHCI_PORT_CMD_FR) {
406 return EFI_SUCCESS;
407 }
408
409 AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE));
410
411 return AhciWaitMmioSet (
412 AhciBar,
413 Offset,
414 EFI_AHCI_PORT_CMD_FR,
415 0,
416 Timeout
417 );
418 }
419
420 /**
421 Build the command list, command table and prepare the fis receiver.
422
423 @param AhciContext The pointer to the AHCI_CONTEXT.
424 @param Port The number of port.
425 @param PortMultiplier The timeout Value of stop.
426 @param CommandFis The control fis will be used for the transfer.
427 @param CommandList The command list will be used for the transfer.
428 @param AtapiCommand The atapi command will be used for the transfer.
429 @param AtapiCommandLength The Length of the atapi command.
430 @param CommandSlotNumber The command slot will be used for the transfer.
431 @param DataPhysicalAddr The pointer to the Data Buffer pci bus master address.
432 @param DataLength The Data count to be transferred.
433
434 **/
435 VOID
436 EFIAPI
437 AhciBuildCommand (
438 IN AHCI_CONTEXT *AhciContext,
439 IN UINT8 Port,
440 IN UINT8 PortMultiplier,
441 IN EFI_AHCI_COMMAND_FIS *CommandFis,
442 IN EFI_AHCI_COMMAND_LIST *CommandList,
443 IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,
444 IN UINT8 AtapiCommandLength,
445 IN UINT8 CommandSlotNumber,
446 IN OUT VOID *DataPhysicalAddr,
447 IN UINT64 DataLength
448 )
449 {
450 EFI_AHCI_REGISTERS *AhciRegisters;
451 UINT32 AhciBar;
452 UINT64 BaseAddr;
453 UINT64 PrdtNumber;
454 UINTN RemainedData;
455 UINTN MemAddr;
456 DATA_64 Data64;
457 UINT32 Offset;
458
459 AhciRegisters = &AhciContext->AhciRegisters;
460 AhciBar = AhciContext->AhciBar;
461
462 //
463 // Filling the PRDT
464 //
465 PrdtNumber = DivU64x32 (DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1, EFI_AHCI_MAX_DATA_PER_PRDT);
466
467 //
468 // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB Data block.
469 // It also limits that the maximum amount of the PRDT entry in the command table
470 // is 65535.
471 //
472 ASSERT (PrdtNumber <= 1);
473
474 Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis);
475
476 BaseAddr = Data64.Uint64;
477
478 ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));
479
480 ZeroMem (AhciRegisters->AhciCommandTable, sizeof (EFI_AHCI_COMMAND_TABLE));
481
482 CommandFis->AhciCFisPmNum = PortMultiplier;
483
484 CopyMem (&AhciRegisters->AhciCommandTable->CommandFis, CommandFis, sizeof (EFI_AHCI_COMMAND_FIS));
485
486 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
487 if (AtapiCommand != NULL) {
488 CopyMem (
489 &AhciRegisters->AhciCommandTable->AtapiCmd,
490 AtapiCommand,
491 AtapiCommandLength
492 );
493
494 CommandList->AhciCmdA = 1;
495 CommandList->AhciCmdP = 1;
496
497 AhciOrReg (AhciBar, Offset, (EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));
498 } else {
499 AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));
500 }
501
502 RemainedData = (UINTN) DataLength;
503 MemAddr = (UINTN) DataPhysicalAddr;
504 CommandList->AhciCmdPrdtl = (UINT32)PrdtNumber;
505
506 AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDbc = (UINT32)RemainedData - 1;
507
508 Data64.Uint64 = (UINT64)MemAddr;
509 AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDba = Data64.Uint32.Lower32;
510 AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDbau = Data64.Uint32.Upper32;
511
512 //
513 // Set the last PRDT to Interrupt On Complete
514 //
515 AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtIoc = 1;
516
517 CopyMem (
518 (VOID *) ((UINTN) AhciRegisters->AhciCmdList + (UINTN) CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)),
519 CommandList,
520 sizeof (EFI_AHCI_COMMAND_LIST)
521 );
522
523 Data64.Uint64 = (UINT64)(UINTN) AhciRegisters->AhciCommandTable;
524 AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba = Data64.Uint32.Lower32;
525 AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtbau = Data64.Uint32.Upper32;
526 AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdPmp = PortMultiplier;
527
528 }
529
530 /**
531 Buid a command FIS.
532
533 @param CmdFis A pointer to the EFI_AHCI_COMMAND_FIS Data structure.
534 @param AtaCommandBlock A pointer to the AhciBuildCommandFis Data structure.
535
536 **/
537 VOID
538 EFIAPI
539 AhciBuildCommandFis (
540 IN OUT EFI_AHCI_COMMAND_FIS *CmdFis,
541 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock
542 )
543 {
544 ZeroMem (CmdFis, sizeof (EFI_AHCI_COMMAND_FIS));
545
546 CmdFis->AhciCFisType = EFI_AHCI_FIS_REGISTER_H2D;
547 //
548 // Indicator it's a command
549 //
550 CmdFis->AhciCFisCmdInd = 0x1;
551 CmdFis->AhciCFisCmd = AtaCommandBlock->AtaCommand;
552
553 CmdFis->AhciCFisFeature = AtaCommandBlock->AtaFeatures;
554 CmdFis->AhciCFisFeatureExp = AtaCommandBlock->AtaFeaturesExp;
555
556 CmdFis->AhciCFisSecNum = AtaCommandBlock->AtaSectorNumber;
557 CmdFis->AhciCFisSecNumExp = AtaCommandBlock->AtaSectorNumberExp;
558
559 CmdFis->AhciCFisClyLow = AtaCommandBlock->AtaCylinderLow;
560 CmdFis->AhciCFisClyLowExp = AtaCommandBlock->AtaCylinderLowExp;
561
562 CmdFis->AhciCFisClyHigh = AtaCommandBlock->AtaCylinderHigh;
563 CmdFis->AhciCFisClyHighExp = AtaCommandBlock->AtaCylinderHighExp;
564
565 CmdFis->AhciCFisSecCount = AtaCommandBlock->AtaSectorCount;
566 CmdFis->AhciCFisSecCountExp = AtaCommandBlock->AtaSectorCountExp;
567
568 CmdFis->AhciCFisDevHead = (UINT8) (AtaCommandBlock->AtaDeviceHead | 0xE0);
569 }
570
571 /**
572 Start a PIO Data transfer on specific port.
573
574 @param AhciContext The pointer to the AHCI_CONTEXT.
575 @param Port The number of port.
576 @param PortMultiplier The timeout Value of stop.
577 @param AtapiCommand The atapi command will be used for the transfer.
578 @param AtapiCommandLength The Length of the atapi command.
579 @param Read The transfer direction.
580 @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK Data.
581 @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK Data.
582 @param MemoryAddr The pointer to the Data Buffer.
583 @param DataCount The Data count to be transferred.
584 @param Timeout The timeout Value of non Data transfer.
585
586 @retval EFI_DEVICE_ERROR The PIO Data transfer abort with error occurs.
587 @retval EFI_TIMEOUT The operation is time out.
588 @retval EFI_UNSUPPORTED The device is not ready for transfer.
589 @retval EFI_SUCCESS The PIO Data transfer executes successfully.
590
591 **/
592 EFI_STATUS
593 EFIAPI
594 AhciPioTransfer (
595 IN AHCI_CONTEXT *AhciContext,
596 IN UINT8 Port,
597 IN UINT8 PortMultiplier,
598 IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,
599 IN UINT8 AtapiCommandLength,
600 IN BOOLEAN Read,
601 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
602 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
603 IN OUT VOID *MemoryAddr,
604 IN UINT32 DataCount,
605 IN UINT64 Timeout
606 )
607 {
608 EFI_STATUS Status;
609 EFI_AHCI_REGISTERS *AhciRegisters;
610 UINT32 AhciBar;
611 UINT32 FisBaseAddr;
612 UINT32 Offset;
613 UINT32 Delay;
614 EFI_AHCI_COMMAND_FIS CFis;
615 EFI_AHCI_COMMAND_LIST CmdList;
616 UINT32 PortTfd;
617 UINT32 PrdCount;
618 UINT32 OldRfisLo;
619 UINT32 OldRfisHi;
620 UINT32 OldCmdListLo;
621 UINT32 OldCmdListHi;
622
623 AhciRegisters = &AhciContext->AhciRegisters;
624 AhciBar = AhciContext->AhciBar;
625
626 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
627 OldRfisLo = AhciReadReg (AhciBar, Offset);
628 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;
629 OldRfisHi = AhciReadReg (AhciBar, Offset);
630 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
631 AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciRFis);
632 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;
633 AhciWriteReg (AhciBar, Offset, 0);
634
635 //
636 // Single task envrionment, we only use one command table for all port
637 //
638 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
639 OldCmdListLo = AhciReadReg (AhciBar, Offset);
640 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;
641 OldCmdListHi = AhciReadReg (AhciBar, Offset);
642 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
643 AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciCmdList);
644 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;
645 AhciWriteReg (AhciBar, Offset, 0);
646
647 //
648 // Package read needed
649 //
650 AhciBuildCommandFis (&CFis, AtaCommandBlock);
651
652 ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));
653
654 CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;
655 CmdList.AhciCmdW = Read ? 0 : 1;
656
657 AhciBuildCommand (
658 AhciContext,
659 Port,
660 PortMultiplier,
661 &CFis,
662 &CmdList,
663 AtapiCommand,
664 AtapiCommandLength,
665 0,
666 MemoryAddr,
667 DataCount
668 );
669
670 Status = AhciStartCommand (
671 AhciBar,
672 Port,
673 0,
674 Timeout
675 );
676 if (EFI_ERROR (Status)) {
677 goto Exit;
678 }
679
680 //
681 // Checking the status and wait the driver sending Data
682 //
683 FisBaseAddr = (UINT32)(UINTN)AhciRegisters->AhciRFis;
684 if (Read && (AtapiCommand == 0)) {
685 //
686 // Wait device sends the PIO setup fis before Data transfer
687 //
688 Status = EFI_TIMEOUT;
689 Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);
690 do {
691 Offset = FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET;
692
693 Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_PIO_SETUP, 0);
694 if (!EFI_ERROR (Status)) {
695 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
696 PortTfd = AhciReadReg (AhciBar, (UINT32) Offset);
697 //
698 // PxTFD will be updated if there is a D2H or SetupFIS received.
699 // For PIO IN transfer, D2H means a device error. Therefore we only need to check the TFD after receiving a SetupFIS.
700 //
701 if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
702 Status = EFI_DEVICE_ERROR;
703 break;
704 }
705
706 PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));
707 if (PrdCount == DataCount) {
708 break;
709 }
710 }
711
712 Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
713 Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, 0);
714 if (!EFI_ERROR (Status)) {
715 Status = EFI_DEVICE_ERROR;
716 break;
717 }
718
719 //
720 // Stall for 100 microseconds.
721 //
722 MicroSecondDelay(100);
723
724 Delay--;
725 } while (Delay > 0);
726 } else {
727 //
728 // Wait for D2H Fis is received
729 //
730 Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
731 Status = AhciWaitMemSet (
732 Offset,
733 EFI_AHCI_FIS_TYPE_MASK,
734 EFI_AHCI_FIS_REGISTER_D2H,
735 Timeout
736 );
737
738 if (EFI_ERROR (Status)) {
739 goto Exit;
740 }
741
742 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
743 PortTfd = AhciReadReg (AhciBar, (UINT32) Offset);
744 if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
745 Status = EFI_DEVICE_ERROR;
746 }
747 }
748
749 Exit:
750 AhciStopCommand (
751 AhciBar,
752 Port,
753 Timeout
754 );
755
756 AhciDisableFisReceive (
757 AhciBar,
758 Port,
759 Timeout
760 );
761
762 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
763 AhciWriteReg (AhciBar, Offset, OldRfisLo);
764 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;
765 AhciWriteReg (AhciBar, Offset, OldRfisHi);
766
767 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
768 AhciWriteReg (AhciBar, Offset, OldCmdListLo);
769 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;
770 AhciWriteReg (AhciBar, Offset, OldCmdListHi);
771
772 return Status;
773 }
774
775 /**
776 Stop command running for giving port
777
778 @param AhciBar AHCI bar address.
779 @param Port The number of port.
780 @param Timeout The timeout Value of stop.
781
782 @retval EFI_DEVICE_ERROR The command stop unsuccessfully.
783 @retval EFI_TIMEOUT The operation is time out.
784 @retval EFI_SUCCESS The command stop successfully.
785
786 **/
787 EFI_STATUS
788 EFIAPI
789 AhciStopCommand (
790 IN UINT32 AhciBar,
791 IN UINT8 Port,
792 IN UINT64 Timeout
793 )
794 {
795 UINT32 Offset;
796 UINT32 Data;
797
798 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
799 Data = AhciReadReg (AhciBar, Offset);
800
801 if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) == 0) {
802 return EFI_SUCCESS;
803 }
804
805 if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) {
806 AhciAndReg (AhciBar, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_ST));
807 }
808
809 return AhciWaitMmioSet (
810 AhciBar,
811 Offset,
812 EFI_AHCI_PORT_CMD_CR,
813 0,
814 Timeout
815 );
816 }
817
818 /**
819 Start command for give slot on specific port.
820
821 @param AhciBar AHCI bar address.
822 @param Port The number of port.
823 @param CommandSlot The number of CommandSlot.
824 @param Timeout The timeout Value of start.
825
826 @retval EFI_DEVICE_ERROR The command start unsuccessfully.
827 @retval EFI_TIMEOUT The operation is time out.
828 @retval EFI_SUCCESS The command start successfully.
829
830 **/
831 EFI_STATUS
832 EFIAPI
833 AhciStartCommand (
834 IN UINT32 AhciBar,
835 IN UINT8 Port,
836 IN UINT8 CommandSlot,
837 IN UINT64 Timeout
838 )
839 {
840 UINT32 CmdSlotBit;
841 EFI_STATUS Status;
842 UINT32 PortStatus;
843 UINT32 StartCmd;
844 UINT32 PortTfd;
845 UINT32 Offset;
846 UINT32 Capability;
847
848 //
849 // Collect AHCI controller information
850 //
851 Capability = AhciReadReg(AhciBar, EFI_AHCI_CAPABILITY_OFFSET);
852
853 CmdSlotBit = (UINT32) (1 << CommandSlot);
854
855 AhciClearPortStatus (
856 AhciBar,
857 Port
858 );
859
860 Status = AhciEnableFisReceive (
861 AhciBar,
862 Port,
863 Timeout
864 );
865
866 if (EFI_ERROR (Status)) {
867 return Status;
868 }
869
870 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
871 PortStatus = AhciReadReg (AhciBar, Offset);
872
873 StartCmd = 0;
874 if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) {
875 StartCmd = AhciReadReg (AhciBar, Offset);
876 StartCmd &= ~EFI_AHCI_PORT_CMD_ICC_MASK;
877 StartCmd |= EFI_AHCI_PORT_CMD_ACTIVE;
878 }
879
880 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
881 PortTfd = AhciReadReg (AhciBar, Offset);
882
883 if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) {
884 if ((Capability & BIT24) != 0) {
885 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
886 AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_COL);
887
888 AhciWaitMmioSet (
889 AhciBar,
890 Offset,
891 EFI_AHCI_PORT_CMD_COL,
892 0,
893 Timeout
894 );
895 }
896 }
897
898 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
899 AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_ST | StartCmd);
900
901 //
902 // Setting the command
903 //
904 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SACT;
905 AhciAndReg (AhciBar, Offset, 0);
906 AhciOrReg (AhciBar, Offset, CmdSlotBit);
907
908 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;
909 AhciAndReg (AhciBar, Offset, 0);
910 AhciOrReg (AhciBar, Offset, CmdSlotBit);
911 return EFI_SUCCESS;
912 }
913
914
915 /**
916 Do AHCI HBA reset.
917
918 @param[in] AhciBar AHCI bar address.
919 @param[in] Timeout The timeout Value of reset.
920
921 @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.
922 @retval EFI_TIMEOUT The reset operation is time out.
923 @retval EFI_SUCCESS AHCI controller is reset successfully.
924
925 **/
926 EFI_STATUS
927 EFIAPI
928 AhciReset (
929 IN UINT32 AhciBar,
930 IN UINT64 Timeout
931 )
932 {
933 UINT32 Delay;
934 UINT32 Value;
935 UINT32 Capability;
936
937 //
938 // Collect AHCI controller information
939 //
940 Capability = AhciReadReg (AhciBar, EFI_AHCI_CAPABILITY_OFFSET);
941
942 //
943 // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set
944 //
945 if ((Capability & EFI_AHCI_CAP_SAM) == 0) {
946 AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);
947 }
948
949 AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);
950
951 Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
952
953 do {
954 Value = AhciReadReg(AhciBar, EFI_AHCI_GHC_OFFSET);
955 if ((Value & EFI_AHCI_GHC_RESET) == 0) {
956 return EFI_SUCCESS;
957 }
958
959 //
960 // Stall for 100 microseconds.
961 //
962 MicroSecondDelay(100);
963
964 Delay--;
965 } while (Delay > 0);
966
967 return EFI_TIMEOUT;
968
969
970 }
971
972 /**
973 Allocate transfer-related data struct which is used at AHCI mode.
974
975 @param[in, out] AhciContext The pointer to the AHCI_CONTEXT.
976
977 @retval EFI_OUT_OF_RESOURCE No enough resource.
978 @retval EFI_SUCCESS Successful to allocate resource.
979
980 **/
981 EFI_STATUS
982 EFIAPI
983 AhciAllocateResource (
984 IN OUT AHCI_CONTEXT *AhciContext
985 )
986 {
987 EFI_STATUS Status;
988 EFI_AHCI_REGISTERS *AhciRegisters;
989 EFI_PHYSICAL_ADDRESS DeviceAddress;
990 VOID *Base;
991 VOID *Mapping;
992
993 AhciRegisters = &AhciContext->AhciRegisters;
994
995 //
996 // Allocate resources required by AHCI host controller.
997 //
998 Status = IoMmuAllocateBuffer (
999 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
1000 &Base,
1001 &DeviceAddress,
1002 &Mapping
1003 );
1004 if (EFI_ERROR (Status)) {
1005 return EFI_OUT_OF_RESOURCES;
1006 }
1007 ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
1008 AhciRegisters->AhciRFisMapping = Mapping;
1009 AhciRegisters->AhciRFis = Base;
1010 ZeroMem (AhciRegisters->AhciRFis, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)));
1011
1012 Status = IoMmuAllocateBuffer (
1013 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),
1014 &Base,
1015 &DeviceAddress,
1016 &Mapping
1017 );
1018 if (EFI_ERROR (Status)) {
1019 IoMmuFreeBuffer (
1020 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
1021 AhciRegisters->AhciRFis,
1022 AhciRegisters->AhciRFisMapping
1023 );
1024 AhciRegisters->AhciRFis = NULL;
1025 return EFI_OUT_OF_RESOURCES;
1026 }
1027 ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
1028 AhciRegisters->AhciCmdListMapping = Mapping;
1029 AhciRegisters->AhciCmdList = Base;
1030 ZeroMem (AhciRegisters->AhciCmdList, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)));
1031
1032 Status = IoMmuAllocateBuffer (
1033 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)),
1034 &Base,
1035 &DeviceAddress,
1036 &Mapping
1037 );
1038 if (EFI_ERROR (Status)) {
1039 IoMmuFreeBuffer (
1040 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),
1041 AhciRegisters->AhciCmdList,
1042 AhciRegisters->AhciCmdListMapping
1043 );
1044 AhciRegisters->AhciCmdList = NULL;
1045 IoMmuFreeBuffer (
1046 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
1047 AhciRegisters->AhciRFis,
1048 AhciRegisters->AhciRFisMapping
1049 );
1050 AhciRegisters->AhciRFis = NULL;
1051 return EFI_OUT_OF_RESOURCES;
1052 }
1053 ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
1054 AhciRegisters->AhciCommandTableMapping = Mapping;
1055 AhciRegisters->AhciCommandTable = Base;
1056 ZeroMem (AhciRegisters->AhciCommandTable, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)));
1057
1058 //
1059 // Allocate resources for data transfer.
1060 //
1061 Status = IoMmuAllocateBuffer (
1062 EFI_SIZE_TO_PAGES (HDD_PAYLOAD),
1063 &Base,
1064 &DeviceAddress,
1065 &Mapping
1066 );
1067 if (EFI_ERROR (Status)) {
1068 IoMmuFreeBuffer (
1069 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
1070 AhciRegisters->AhciCommandTable,
1071 AhciRegisters->AhciCommandTableMapping
1072 );
1073 AhciRegisters->AhciCommandTable = NULL;
1074 IoMmuFreeBuffer (
1075 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),
1076 AhciRegisters->AhciCmdList,
1077 AhciRegisters->AhciCmdListMapping
1078 );
1079 AhciRegisters->AhciCmdList = NULL;
1080 IoMmuFreeBuffer (
1081 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
1082 AhciRegisters->AhciRFis,
1083 AhciRegisters->AhciRFisMapping
1084 );
1085 AhciRegisters->AhciRFis = NULL;
1086 return EFI_OUT_OF_RESOURCES;
1087 }
1088 ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) Base));
1089 AhciContext->BufferMapping = Mapping;
1090 AhciContext->Buffer = Base;
1091 ZeroMem (AhciContext->Buffer, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (HDD_PAYLOAD));
1092
1093 DEBUG ((
1094 DEBUG_INFO,
1095 "%a() AhciContext 0x%x 0x%x 0x%x 0x%x\n",
1096 __FUNCTION__,
1097 AhciContext->Buffer,
1098 AhciRegisters->AhciRFis,
1099 AhciRegisters->AhciCmdList,
1100 AhciRegisters->AhciCommandTable
1101 ));
1102 return EFI_SUCCESS;
1103 }
1104
1105 /**
1106 Free allocated transfer-related data struct which is used at AHCI mode.
1107
1108 @param[in, out] AhciContext The pointer to the AHCI_CONTEXT.
1109
1110 **/
1111 VOID
1112 EFIAPI
1113 AhciFreeResource (
1114 IN OUT AHCI_CONTEXT *AhciContext
1115 )
1116 {
1117 EFI_AHCI_REGISTERS *AhciRegisters;
1118
1119 AhciRegisters = &AhciContext->AhciRegisters;
1120
1121 if (AhciContext->Buffer != NULL) {
1122 IoMmuFreeBuffer (
1123 EFI_SIZE_TO_PAGES (HDD_PAYLOAD),
1124 AhciContext->Buffer,
1125 AhciContext->BufferMapping
1126 );
1127 AhciContext->Buffer = NULL;
1128 }
1129
1130 if (AhciRegisters->AhciCommandTable != NULL) {
1131 IoMmuFreeBuffer (
1132 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)),
1133 AhciRegisters->AhciCommandTable,
1134 AhciRegisters->AhciCommandTableMapping
1135 );
1136 AhciRegisters->AhciCommandTable = NULL;
1137 }
1138
1139 if (AhciRegisters->AhciCmdList != NULL) {
1140 IoMmuFreeBuffer (
1141 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),
1142 AhciRegisters->AhciCmdList,
1143 AhciRegisters->AhciCmdListMapping
1144 );
1145 AhciRegisters->AhciCmdList = NULL;
1146 }
1147
1148 if (AhciRegisters->AhciRFis != NULL) {
1149 IoMmuFreeBuffer (
1150 EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
1151 AhciRegisters->AhciRFis,
1152 AhciRegisters->AhciRFisMapping
1153 );
1154 AhciRegisters->AhciRFis = NULL;
1155 }
1156 }
1157
1158 /**
1159 Initialize ATA host controller at AHCI mode.
1160
1161 The function is designed to initialize ATA host controller.
1162
1163 @param[in] AhciContext The pointer to the AHCI_CONTEXT.
1164 @param[in] Port The port number to do initialization.
1165
1166 **/
1167 EFI_STATUS
1168 EFIAPI
1169 AhciModeInitialize (
1170 IN AHCI_CONTEXT *AhciContext,
1171 IN UINT8 Port
1172 )
1173 {
1174 EFI_STATUS Status;
1175 EFI_AHCI_REGISTERS *AhciRegisters;
1176 UINT32 AhciBar;
1177 UINT32 Capability;
1178 UINT32 Offset;
1179 UINT32 Data;
1180 UINT32 PhyDetectDelay;
1181
1182 AhciRegisters = &AhciContext->AhciRegisters;
1183 AhciBar = AhciContext->AhciBar;
1184
1185 Status = AhciReset (AhciBar, ATA_TIMEOUT);
1186 if (EFI_ERROR (Status)) {
1187 return Status;
1188 }
1189
1190 //
1191 // Collect AHCI controller information
1192 //
1193 Capability = AhciReadReg (AhciBar, EFI_AHCI_CAPABILITY_OFFSET);
1194
1195 //
1196 // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set
1197 //
1198 if ((Capability & EFI_AHCI_CAP_SAM) == 0) {
1199 AhciOrReg (AhciBar, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);
1200 }
1201
1202 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
1203 AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciRFis);
1204
1205 //
1206 // Single task envrionment, we only use one command table for all port
1207 //
1208 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
1209 AhciWriteReg (AhciBar, Offset, (UINT32)(UINTN)AhciRegisters->AhciCmdList);
1210
1211 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
1212 Data = AhciReadReg (AhciBar, Offset);
1213 if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {
1214 AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_POD);
1215 }
1216
1217 if ((Capability & BIT27) != 0) {
1218 AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_CMD_SUD);
1219 }
1220
1221 //
1222 // Disable aggressive power management.
1223 //
1224 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;
1225 AhciOrReg (AhciBar, Offset, EFI_AHCI_PORT_SCTL_IPM_INIT);
1226 //
1227 // Disable the reporting of the corresponding interrupt to system software.
1228 //
1229 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;
1230 AhciAndReg (AhciBar, Offset, 0);
1231
1232 Status = AhciEnableFisReceive (
1233 AhciBar,
1234 Port,
1235 5000000
1236 );
1237 ASSERT_EFI_ERROR (Status);
1238 if (EFI_ERROR (Status)) {
1239 return Status;
1240 }
1241
1242 //
1243 // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ
1244 // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.
1245 //
1246 PhyDetectDelay = 16 * 1000;
1247 do {
1248 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;
1249 if (AhciReadReg(AhciBar, Offset) != 0) {
1250 AhciWriteReg (AhciBar, Offset, AhciReadReg(AhciBar, Offset));
1251 }
1252 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
1253
1254 Data = AhciReadReg (AhciBar, Offset) & EFI_AHCI_PORT_TFD_MASK;
1255 if (Data == 0) {
1256 break;
1257 }
1258
1259 MicroSecondDelay (1000);
1260 PhyDetectDelay--;
1261 } while (PhyDetectDelay > 0);
1262
1263 if (PhyDetectDelay == 0) {
1264 return EFI_NOT_FOUND;
1265 }
1266
1267 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;
1268 Status = AhciWaitMmioSet (
1269 AhciBar,
1270 Offset,
1271 0x0000FFFF,
1272 0x00000101,
1273 160000000
1274 );
1275
1276 if (EFI_ERROR (Status)) {
1277 return Status;
1278 }
1279
1280 return Status;
1281 }
1282